From f9ab90d9d6d02989a075d0f0074496d5b1045e4b Mon Sep 17 00:00:00 2001 From: rgrimes Date: Fri, 27 May 1994 12:33:43 +0000 Subject: BSD 4.4 Lite Usr.bin Sources --- usr.bin/Makefile | 38 + usr.bin/Makefile.inc | 3 + usr.bin/apply/Makefile | 5 + usr.bin/apply/apply.1 | 129 + usr.bin/apply/apply.c | 234 + usr.bin/apropos/Makefile | 7 + usr.bin/apropos/apropos.1 | 120 + usr.bin/apropos/apropos.c | 223 + usr.bin/ar/Makefile | 16 + usr.bin/ar/append.c | 89 + usr.bin/ar/ar.1 | 257 ++ usr.bin/ar/ar.5.5 | 145 + usr.bin/ar/ar.c | 237 + usr.bin/ar/archive.c | 325 ++ usr.bin/ar/archive.h | 105 + usr.bin/ar/contents.c | 96 + usr.bin/ar/delete.c | 96 + usr.bin/ar/extern.h | 54 + usr.bin/ar/extract.c | 128 + usr.bin/ar/misc.c | 148 + usr.bin/ar/move.c | 140 + usr.bin/ar/pathnames.h | 40 + usr.bin/ar/print.c | 90 + usr.bin/ar/replace.c | 176 + usr.bin/banner/Makefile | 6 + usr.bin/banner/banner.6 | 72 + usr.bin/banner/banner.c | 1160 +++++ usr.bin/basename/Makefile | 6 + usr.bin/basename/basename.1 | 97 + usr.bin/basename/basename.c | 138 + usr.bin/bdes/Makefile | 5 + usr.bin/bdes/bdes.1 | 304 ++ usr.bin/bdes/bdes.c | 1046 +++++ usr.bin/bdes/bdes.ps | 2945 ++++++++++++ usr.bin/biff/Makefile | 5 + usr.bin/biff/biff.1 | 86 + usr.bin/biff/biff.c | 114 + usr.bin/cal/Makefile | 5 + usr.bin/cal/README | 42 + usr.bin/cal/cal.1 | 81 + usr.bin/cal/cal.c | 427 ++ usr.bin/calendar/Makefile | 9 + usr.bin/calendar/calendar.1 | 145 + usr.bin/calendar/calendar.c | 411 ++ usr.bin/calendar/calendars/calendar.birthday | 257 ++ usr.bin/calendar/calendars/calendar.christian | 16 + usr.bin/calendar/calendars/calendar.computer | 62 + usr.bin/calendar/calendars/calendar.history | 486 ++ usr.bin/calendar/calendars/calendar.holiday | 568 +++ usr.bin/calendar/calendars/calendar.judaic | 30 + usr.bin/calendar/calendars/calendar.music | 178 + usr.bin/calendar/calendars/calendar.usholiday | 31 + usr.bin/calendar/pathnames.h | 40 + usr.bin/cap_mkdb/Makefile | 5 + usr.bin/cap_mkdb/cap_mkdb.1 | 101 + usr.bin/cap_mkdb/cap_mkdb.c | 250 ++ usr.bin/checknr/Makefile | 5 + usr.bin/checknr/checknr.1 | 159 + usr.bin/checknr/checknr.c | 586 +++ usr.bin/chflags/Makefile | 7 + usr.bin/chflags/chflags.1 | 123 + usr.bin/chflags/chflags.c | 180 + usr.bin/chpass/Makefile | 15 + usr.bin/chpass/chpass.1 | 231 + usr.bin/chpass/chpass.c | 192 + usr.bin/chpass/chpass.h | 70 + usr.bin/chpass/edit.c | 213 + usr.bin/chpass/field.c | 268 ++ usr.bin/chpass/pathnames.h | 39 + usr.bin/chpass/pw_copy.c | 107 + usr.bin/chpass/pw_copy.h | 36 + usr.bin/chpass/table.c | 60 + usr.bin/chpass/util.c | 145 + usr.bin/cksum/Makefile | 6 + usr.bin/cksum/cksum.1 | 164 + usr.bin/cksum/cksum.c | 124 + usr.bin/cksum/crc.c | 140 + usr.bin/cksum/extern.h | 45 + usr.bin/cksum/print.c | 73 + usr.bin/cksum/sum1.c | 69 + usr.bin/cksum/sum2.c | 71 + usr.bin/cmp/Makefile | 6 + usr.bin/cmp/cmp.1 | 107 + usr.bin/cmp/cmp.c | 146 + usr.bin/cmp/extern.h | 45 + usr.bin/cmp/misc.c | 64 + usr.bin/cmp/regular.c | 98 + usr.bin/cmp/special.c | 99 + usr.bin/col/Makefile | 5 + usr.bin/col/README | 48 + usr.bin/col/col.1 | 126 + usr.bin/col/col.c | 534 +++ usr.bin/colcrt/Makefile | 5 + usr.bin/colcrt/colcrt.1 | 108 + usr.bin/colcrt/colcrt.c | 251 ++ usr.bin/colrm/Makefile | 5 + usr.bin/colrm/colrm.1 | 78 + usr.bin/colrm/colrm.c | 167 + usr.bin/column/Makefile | 5 + usr.bin/column/column.1 | 99 + usr.bin/column/column.c | 304 ++ usr.bin/comm/Makefile | 5 + usr.bin/comm/comm.1 | 94 + usr.bin/comm/comm.c | 186 + usr.bin/compress/Makefile | 12 + usr.bin/compress/compress.1 | 172 + usr.bin/compress/compress.c | 444 ++ usr.bin/compress/doc/NOTES | 139 + usr.bin/compress/doc/README | 283 ++ usr.bin/compress/doc/revision.log | 116 + usr.bin/compress/zcat.sh | 37 + usr.bin/compress/zopen.3 | 139 + usr.bin/compress/zopen.c | 740 +++ usr.bin/cpp/Makefile | 17 + usr.bin/cpp/cpp.notraditional.sh | 91 + usr.bin/cpp/cpp.sh | 91 + usr.bin/ctags/C.c | 501 +++ usr.bin/ctags/Makefile | 7 + usr.bin/ctags/ctags.1 | 214 + usr.bin/ctags/ctags.c | 272 ++ usr.bin/ctags/ctags.h | 90 + usr.bin/ctags/fortran.c | 168 + usr.bin/ctags/lisp.c | 105 + usr.bin/ctags/print.c | 115 + usr.bin/ctags/test/ctags.test | 67 + usr.bin/ctags/tree.c | 135 + usr.bin/ctags/yacc.c | 151 + usr.bin/cut/Makefile | 5 + usr.bin/cut/cut.1 | 110 + usr.bin/cut/cut.c | 296 ++ usr.bin/diff/diff/diff.1 | 387 ++ usr.bin/diff/diff3/diff3.1 | 172 + usr.bin/dirname/Makefile | 6 + usr.bin/dirname/dirname.c | 144 + usr.bin/du/Makefile | 5 + usr.bin/du/du.1 | 117 + usr.bin/du/du.c | 229 + usr.bin/env/Makefile | 6 + usr.bin/env/env.c | 82 + usr.bin/error/Makefile | 6 + usr.bin/error/error.1 | 304 ++ usr.bin/error/error.h | 224 + usr.bin/error/filter.c | 194 + usr.bin/error/input.c | 548 +++ usr.bin/error/main.c | 287 ++ usr.bin/error/pathnames.h | 43 + usr.bin/error/pi.c | 404 ++ usr.bin/error/subr.c | 423 ++ usr.bin/error/touch.c | 768 ++++ usr.bin/expand/Makefile | 6 + usr.bin/expand/expand.1 | 87 + usr.bin/expand/expand.c | 152 + usr.bin/false/Makefile | 5 + usr.bin/false/false.1 | 63 + usr.bin/false/false.c | 47 + usr.bin/find/Makefile | 6 + usr.bin/find/extern.h | 78 + usr.bin/find/find.1 | 454 ++ usr.bin/find/find.c | 192 + usr.bin/find/find.h | 107 + usr.bin/find/function.c | 1069 +++++ usr.bin/find/ls.c | 118 + usr.bin/find/main.c | 153 + usr.bin/find/misc.c | 127 + usr.bin/find/operator.c | 270 ++ usr.bin/find/option.c | 150 + usr.bin/finger/Makefile | 6 + usr.bin/finger/extern.h | 50 + usr.bin/finger/finger.1 | 161 + usr.bin/finger/finger.c | 257 ++ usr.bin/finger/finger.h | 63 + usr.bin/finger/lprint.c | 333 ++ usr.bin/finger/net.c | 148 + usr.bin/finger/sprint.c | 148 + usr.bin/finger/util.c | 381 ++ usr.bin/fmt/Makefile | 7 + usr.bin/fmt/fmt.1 | 89 + usr.bin/fmt/fmt.c | 467 ++ usr.bin/fold/Makefile | 5 + usr.bin/fold/fold.1 | 64 + usr.bin/fold/fold.c | 152 + usr.bin/fpr/Makefile | 5 + usr.bin/fpr/fpr.1 | 83 + usr.bin/fpr/fpr.c | 410 ++ usr.bin/from/Makefile | 5 + usr.bin/from/from.1 | 83 + usr.bin/from/from.c | 136 + usr.bin/fsplit/Makefile | 5 + usr.bin/fsplit/fsplit.1 | 103 + usr.bin/fsplit/fsplit.c | 408 ++ usr.bin/fstat/Makefile | 10 + usr.bin/fstat/fstat.1 | 219 + usr.bin/fstat/fstat.c | 746 ++++ usr.bin/ftp/Makefile | 6 + usr.bin/ftp/cmds.c | 2206 +++++++++ usr.bin/ftp/cmdtab.c | 186 + usr.bin/ftp/domacro.c | 148 + usr.bin/ftp/extern.h | 152 + usr.bin/ftp/ftp.1 | 1136 +++++ usr.bin/ftp/ftp.c | 1470 ++++++ usr.bin/ftp/ftp_var.h | 125 + usr.bin/ftp/main.c | 514 +++ usr.bin/ftp/pathnames.h | 39 + usr.bin/ftp/ruserpass.c | 281 ++ usr.bin/gcore/Makefile | 7 + usr.bin/gcore/extern.h | 37 + usr.bin/gcore/gcore.1 | 90 + usr.bin/gcore/gcore.c | 313 ++ usr.bin/gcore/md-nop.c | 53 + usr.bin/gcore/md-sparc.c | 186 + usr.bin/gprof/Makefile | 12 + usr.bin/gprof/PSD.doc/Makefile | 12 + usr.bin/gprof/PSD.doc/abstract.me | 66 + usr.bin/gprof/PSD.doc/gathering.me | 231 + usr.bin/gprof/PSD.doc/header.me | 38 + usr.bin/gprof/PSD.doc/intro.me | 81 + usr.bin/gprof/PSD.doc/postp.me | 190 + usr.bin/gprof/PSD.doc/postp1.pic | 54 + usr.bin/gprof/PSD.doc/postp2.pic | 56 + usr.bin/gprof/PSD.doc/postp3.pic | 51 + usr.bin/gprof/PSD.doc/pres1.pic | 56 + usr.bin/gprof/PSD.doc/pres2.pic | 52 + usr.bin/gprof/PSD.doc/present.me | 306 ++ usr.bin/gprof/PSD.doc/profiling.me | 115 + usr.bin/gprof/PSD.doc/refs.me | 63 + usr.bin/gprof/arcs.c | 950 ++++ usr.bin/gprof/dfn.c | 325 ++ usr.bin/gprof/gprof.1 | 281 ++ usr.bin/gprof/gprof.c | 749 ++++ usr.bin/gprof/gprof.callg | 108 + usr.bin/gprof/gprof.flat | 32 + usr.bin/gprof/gprof.h | 347 ++ usr.bin/gprof/hertz.c | 59 + usr.bin/gprof/hp300.c | 11 + usr.bin/gprof/hp300.h | 44 + usr.bin/gprof/i386.c | 11 + usr.bin/gprof/i386.h | 44 + usr.bin/gprof/lookup.c | 115 + usr.bin/gprof/mips.c | 112 + usr.bin/gprof/mips.h | 50 + usr.bin/gprof/pathnames.h | 38 + usr.bin/gprof/printgprof.c | 718 +++ usr.bin/gprof/printlist.c | 91 + usr.bin/gprof/sparc.c | 110 + usr.bin/gprof/sparc.h | 48 + usr.bin/gprof/tahoe.c | 349 ++ usr.bin/gprof/tahoe.h | 59 + usr.bin/gprof/vax.c | 347 ++ usr.bin/gprof/vax.h | 65 + usr.bin/grep/egrep/Makefile | 17 + usr.bin/grep/egrep/egrep.c | 924 ++++ usr.bin/grep/egrep/grep.1 | 250 ++ usr.bin/grep/egrep/pathnames.h | 40 + usr.bin/head/Makefile | 5 + usr.bin/head/head.1 | 69 + usr.bin/head/head.c | 180 + usr.bin/hexdump/Makefile | 8 + usr.bin/hexdump/conv.c | 128 + usr.bin/hexdump/display.c | 379 ++ usr.bin/hexdump/hexdump.1 | 324 ++ usr.bin/hexdump/hexdump.c | 112 + usr.bin/hexdump/hexdump.h | 98 + usr.bin/hexdump/hexsyntax.c | 127 + usr.bin/hexdump/od.1 | 76 + usr.bin/hexdump/odsyntax.c | 263 ++ usr.bin/hexdump/parse.c | 507 +++ usr.bin/id/Makefile | 14 + usr.bin/id/groups.1 | 63 + usr.bin/id/groups.sh | 37 + usr.bin/id/id.1 | 139 + usr.bin/id/id.c | 351 ++ usr.bin/id/whoami.1 | 61 + usr.bin/id/whoami.sh | 37 + usr.bin/indent/Makefile | 6 + usr.bin/indent/README | 97 + usr.bin/indent/args.c | 300 ++ usr.bin/indent/indent.1 | 452 ++ usr.bin/indent/indent.c | 1181 +++++ usr.bin/indent/indent_codes.h | 69 + usr.bin/indent/indent_globs.h | 310 ++ usr.bin/indent/io.c | 625 +++ usr.bin/indent/lexi.c | 559 +++ usr.bin/indent/parse.c | 324 ++ usr.bin/indent/pr_comment.c | 418 ++ usr.bin/join/Makefile | 5 + usr.bin/join/join.1 | 206 + usr.bin/join/join.c | 582 +++ usr.bin/jot/Makefile | 5 + usr.bin/jot/jot.1 | 195 + usr.bin/jot/jot.c | 393 ++ usr.bin/kdump/Makefile | 12 + usr.bin/kdump/kdump.1 | 100 + usr.bin/kdump/kdump.c | 437 ++ usr.bin/kdump/mkioctls | 33 + usr.bin/ktrace/Makefile | 6 + usr.bin/ktrace/ktrace.1 | 163 + usr.bin/ktrace/ktrace.c | 176 + usr.bin/ktrace/ktrace.h | 41 + usr.bin/ktrace/subr.c | 107 + usr.bin/lam/Makefile | 5 + usr.bin/lam/lam.1 | 127 + usr.bin/lam/lam.c | 233 + usr.bin/last/Makefile | 5 + usr.bin/last/last.1 | 123 + usr.bin/last/last.c | 420 ++ usr.bin/lastcomm/Makefile | 5 + usr.bin/lastcomm/lastcomm.1 | 124 + usr.bin/lastcomm/lastcomm.c | 222 + usr.bin/lastcomm/pathnames.h | 38 + usr.bin/ld/Makefile | 7 + usr.bin/ld/cplus-dem.c | 970 ++++ usr.bin/ld/ld.c | 4718 ++++++++++++++++++++ usr.bin/ld/symseg.h | 358 ++ usr.bin/leave/Makefile | 5 + usr.bin/leave/leave.1 | 102 + usr.bin/leave/leave.c | 163 + usr.bin/locate/Makefile | 5 + usr.bin/locate/bigram/Makefile | 7 + usr.bin/locate/bigram/locate.bigram.c | 84 + usr.bin/locate/code/Makefile | 8 + usr.bin/locate/code/locate.code.c | 212 + usr.bin/locate/locate/Makefile | 10 + usr.bin/locate/locate/locate.1 | 81 + usr.bin/locate/locate/locate.c | 196 + usr.bin/locate/locate/locate.h | 41 + usr.bin/locate/locate/pathnames.h | 36 + usr.bin/locate/locate/updatedb.csh | 77 + usr.bin/lock/Makefile | 7 + usr.bin/lock/lock.1 | 68 + usr.bin/lock/lock.c | 223 + usr.bin/logger/Makefile | 5 + usr.bin/logger/logger.1 | 100 + usr.bin/logger/logger.c | 192 + usr.bin/login/Makefile | 12 + usr.bin/login/klogin.c | 190 + usr.bin/login/login.1 | 146 + usr.bin/login/login.c | 594 +++ usr.bin/login/pathnames.h | 39 + usr.bin/logname/Makefile | 5 + usr.bin/logname/logname.1 | 76 + usr.bin/logname/logname.c | 81 + usr.bin/look/Makefile | 5 + usr.bin/look/look.1 | 104 + usr.bin/look/look.c | 357 ++ usr.bin/look/pathnames.h | 36 + usr.bin/lorder/Makefile | 17 + usr.bin/lorder/lorder.1 | 73 + usr.bin/lorder/lorder.sh | 89 + usr.bin/m4/serv.c | 475 ++ usr.bin/mail/Makefile | 19 + usr.bin/mail/USD.doc/Makefile | 11 + usr.bin/mail/USD.doc/mail0.nr | 71 + usr.bin/mail/USD.doc/mail1.nr | 92 + usr.bin/mail/USD.doc/mail2.nr | 617 +++ usr.bin/mail/USD.doc/mail3.nr | 133 + usr.bin/mail/USD.doc/mail4.nr | 437 ++ usr.bin/mail/USD.doc/mail5.nr | 1041 +++++ usr.bin/mail/USD.doc/mail6.nr | 125 + usr.bin/mail/USD.doc/mail7.nr | 107 + usr.bin/mail/USD.doc/mail8.nr | 75 + usr.bin/mail/USD.doc/mail9.nr | 203 + usr.bin/mail/USD.doc/maila.nr | 33 + usr.bin/mail/aux.c | 705 +++ usr.bin/mail/cmd1.c | 451 ++ usr.bin/mail/cmd2.c | 530 +++ usr.bin/mail/cmd3.c | 730 +++ usr.bin/mail/cmdtab.c | 117 + usr.bin/mail/collect.c | 635 +++ usr.bin/mail/def.h | 276 ++ usr.bin/mail/edit.c | 220 + usr.bin/mail/extern.h | 253 ++ usr.bin/mail/fio.c | 431 ++ usr.bin/mail/getname.c | 72 + usr.bin/mail/glob.h | 100 + usr.bin/mail/head.c | 254 ++ usr.bin/mail/lex.c | 665 +++ usr.bin/mail/list.c | 801 ++++ usr.bin/mail/mail.1 | 1030 +++++ usr.bin/mail/main.c | 296 ++ usr.bin/mail/misc/mail.help | 23 + usr.bin/mail/misc/mail.rc | 2 + usr.bin/mail/misc/mail.tildehelp | 22 + usr.bin/mail/names.c | 694 +++ usr.bin/mail/pathnames.h | 42 + usr.bin/mail/popen.c | 373 ++ usr.bin/mail/quit.c | 491 ++ usr.bin/mail/rcv.h | 44 + usr.bin/mail/send.c | 556 +++ usr.bin/mail/strings.c | 129 + usr.bin/mail/temp.c | 111 + usr.bin/mail/tty.c | 273 ++ usr.bin/mail/v7.local.c | 83 + usr.bin/mail/vars.c | 190 + usr.bin/mail/version.c | 42 + usr.bin/make/Makefile.dist | 7 + usr.bin/make/bit.h | 100 + usr.bin/man/Makefile | 8 + usr.bin/man/config.c | 174 + usr.bin/man/config.h | 57 + usr.bin/man/man.1 | 188 + usr.bin/man/man.c | 712 +++ usr.bin/man/man.conf | 46 + usr.bin/man/man.conf.5 | 195 + usr.bin/man/pathnames.h | 39 + usr.bin/mesg/Makefile | 5 + usr.bin/mesg/mesg.1 | 91 + usr.bin/mesg/mesg.c | 104 + usr.bin/mkdep/Makefile | 16 + usr.bin/mkdep/mkdep.1 | 103 + usr.bin/mkdep/mkdep.append | 123 + usr.bin/mkdep/mkdep.gcc.sh | 93 + usr.bin/mkdep/mkdep.old.compiler | 143 + usr.bin/mkdep/mkdep.sh | 111 + usr.bin/mkdep/mkdep.ultrix | 124 + usr.bin/mkfifo/Makefile | 5 + usr.bin/mkfifo/mkfifo.1 | 72 + usr.bin/mkfifo/mkfifo.c | 82 + usr.bin/mklocale/Japanese | 158 + usr.bin/mklocale/Makefile | 8 + usr.bin/mklocale/POSIX | 33 + usr.bin/mklocale/ldef.h | 53 + usr.bin/mklocale/lex.l | 152 + usr.bin/mklocale/mklocale.1 | 257 ++ usr.bin/mklocale/yacc.y | 821 ++++ usr.bin/mkstr/Makefile | 5 + usr.bin/mkstr/mkstr.1 | 137 + usr.bin/mkstr/mkstr.c | 310 ++ usr.bin/more/Makefile | 15 + usr.bin/more/ch.c | 454 ++ usr.bin/more/command.c | 655 +++ usr.bin/more/decode.c | 201 + usr.bin/more/help.c | 49 + usr.bin/more/input.c | 241 + usr.bin/more/less.h | 87 + usr.bin/more/line.c | 508 +++ usr.bin/more/linenum.c | 383 ++ usr.bin/more/main.c | 367 ++ usr.bin/more/more.1 | 298 ++ usr.bin/more/more.help | 39 + usr.bin/more/option.c | 128 + usr.bin/more/os.c | 283 ++ usr.bin/more/output.c | 252 ++ usr.bin/more/pathnames.h | 38 + usr.bin/more/position.c | 163 + usr.bin/more/prim.c | 834 ++++ usr.bin/more/screen.c | 587 +++ usr.bin/more/signal.c | 220 + usr.bin/more/tags.c | 205 + usr.bin/more/ttyin.c | 79 + usr.bin/msgs/Makefile | 7 + usr.bin/msgs/msgs.1 | 214 + usr.bin/msgs/msgs.c | 863 ++++ usr.bin/msgs/pathnames.h | 40 + usr.bin/mt/Makefile | 6 + usr.bin/mt/mt.1 | 130 + usr.bin/mt/mt.c | 274 ++ usr.bin/netstat/Makefile | 13 + usr.bin/netstat/if.c | 375 ++ usr.bin/netstat/inet.c | 494 ++ usr.bin/netstat/iso.c | 842 ++++ usr.bin/netstat/main.c | 508 +++ usr.bin/netstat/mbuf.c | 122 + usr.bin/netstat/mroute.c | 222 + usr.bin/netstat/netstat.1 | 289 ++ usr.bin/netstat/netstat.h | 109 + usr.bin/netstat/ns.c | 351 ++ usr.bin/netstat/route.c | 666 +++ usr.bin/netstat/unix.c | 134 + usr.bin/nfsstat/Makefile | 10 + usr.bin/nfsstat/nfsstat.1 | 88 + usr.bin/nfsstat/nfsstat.c | 360 ++ usr.bin/nice/Makefile | 5 + usr.bin/nice/nice.1 | 97 + usr.bin/nice/nice.c | 93 + usr.bin/nm/Makefile | 5 + usr.bin/nm/nm.1 | 117 + usr.bin/nm/nm.c | 584 +++ usr.bin/nohup/Makefile | 5 + usr.bin/nohup/nohup.1 | 90 + usr.bin/nohup/nohup.c | 117 + usr.bin/pagesize/Makefile | 17 + usr.bin/pagesize/pagesize.1 | 56 + usr.bin/pagesize/pagesize.sh | 40 + usr.bin/passwd/Makefile | 15 + usr.bin/passwd/extern.h | 37 + usr.bin/passwd/kpasswd_proto.h | 54 + usr.bin/passwd/krb_passwd.c | 319 ++ usr.bin/passwd/local_passwd.c | 153 + usr.bin/passwd/passwd.1 | 107 + usr.bin/passwd/passwd.c | 118 + usr.bin/paste/Makefile | 5 + usr.bin/paste/paste.1 | 119 + usr.bin/paste/paste.c | 251 ++ usr.bin/patch/EXTERN.h | 15 + usr.bin/patch/INTERN.h | 15 + usr.bin/patch/config.h | 16 + usr.bin/patch/patchlevel.h | 1 + usr.bin/patch/version.c | 28 + usr.bin/patch/version.h | 9 + usr.bin/pr/Makefile | 6 + usr.bin/pr/egetopt.c | 215 + usr.bin/pr/extern.h | 60 + usr.bin/pr/pr.1 | 347 ++ usr.bin/pr/pr.c | 1804 ++++++++ usr.bin/pr/pr.h | 72 + usr.bin/printenv/Makefile | 6 + usr.bin/printenv/printenv.1 | 98 + usr.bin/printenv/printenv.c | 99 + usr.bin/printf/Makefile | 5 + usr.bin/printf/printf.1 | 272 ++ usr.bin/printf/printf.c | 410 ++ usr.bin/quota/Makefile | 7 + usr.bin/quota/quota.1 | 131 + usr.bin/quota/quota.c | 510 +++ usr.bin/ranlib/Makefile | 16 + usr.bin/ranlib/build.c | 283 ++ usr.bin/ranlib/misc.c | 104 + usr.bin/ranlib/pathnames.h | 36 + usr.bin/ranlib/ranlib.1 | 87 + usr.bin/ranlib/ranlib.5.5 | 70 + usr.bin/ranlib/ranlib.c | 89 + usr.bin/ranlib/touch.c | 84 + usr.bin/rdist/Makefile | 14 + usr.bin/rdist/cron.entry | 1 + usr.bin/rdist/defs.h | 180 + usr.bin/rdist/docmd.c | 629 +++ usr.bin/rdist/expand.c | 666 +++ usr.bin/rdist/gram.y | 508 +++ usr.bin/rdist/lookup.c | 166 + usr.bin/rdist/main.c | 327 ++ usr.bin/rdist/pathnames.h | 38 + usr.bin/rdist/rdist.1 | 412 ++ usr.bin/rdist/server.c | 1584 +++++++ usr.bin/renice/Makefile | 5 + usr.bin/renice/renice.8 | 131 + usr.bin/renice/renice.c | 128 + usr.bin/rev/Makefile | 5 + usr.bin/rev/rev.1 | 48 + usr.bin/rev/rev.c | 109 + usr.bin/rlogin/Makefile | 12 + usr.bin/rlogin/des_rw.c | 203 + usr.bin/rlogin/kcmd.c | 307 ++ usr.bin/rlogin/krb.h | 51 + usr.bin/rlogin/krcmd.c | 158 + usr.bin/rlogin/rlogin.1 | 183 + usr.bin/rlogin/rlogin.c | 941 ++++ usr.bin/rs/Makefile | 5 + usr.bin/rs/rs.1 | 197 + usr.bin/rs/rs.c | 546 +++ usr.bin/rsh/Makefile | 13 + usr.bin/rsh/pathnames.h | 36 + usr.bin/rsh/rsh.1 | 181 + usr.bin/rsh/rsh.c | 480 ++ usr.bin/ruptime/Makefile | 5 + usr.bin/ruptime/ruptime.1 | 81 + usr.bin/ruptime/ruptime.c | 281 ++ usr.bin/rwho/Makefile | 5 + usr.bin/rwho/rwho.1 | 80 + usr.bin/rwho/rwho.c | 184 + usr.bin/sccs/Makefile | 5 + usr.bin/sccs/PSD.doc/Makefile | 10 + usr.bin/sccs/PSD.doc/sccs.me | 1608 +++++++ usr.bin/sccs/PSD.doc/spell.ok | 77 + usr.bin/sccs/pathnames.h | 51 + usr.bin/sccs/sccs.1 | 398 ++ usr.bin/sccs/sccs.c | 1621 +++++++ usr.bin/script/Makefile | 7 + usr.bin/script/script.1 | 123 + usr.bin/script/script.c | 268 ++ usr.bin/sed/Makefile | 6 + usr.bin/sed/POSIX | 198 + usr.bin/sed/TEST/hanoi.sed | 102 + usr.bin/sed/TEST/math.sed | 163 + usr.bin/sed/TEST/sed.test | 552 +++ usr.bin/sed/compile.c | 771 ++++ usr.bin/sed/defs.h | 144 + usr.bin/sed/extern.h | 59 + usr.bin/sed/main.c | 352 ++ usr.bin/sed/misc.c | 141 + usr.bin/sed/process.c | 629 +++ usr.bin/sed/sed.1 | 514 +++ usr.bin/shar/Makefile | 16 + usr.bin/shar/shar.1 | 102 + usr.bin/shar/shar.sh | 74 + usr.bin/showmount/Makefile | 7 + usr.bin/showmount/showmount.8 | 88 + usr.bin/showmount/showmount.c | 351 ++ usr.bin/size/Makefile | 5 + usr.bin/size/size.1 | 60 + usr.bin/size/size.c | 149 + usr.bin/soelim/Makefile | 5 + usr.bin/soelim/soelim.1 | 88 + usr.bin/soelim/soelim.c | 160 + usr.bin/split/Makefile | 5 + usr.bin/split/split.1 | 99 + usr.bin/split/split.c | 288 ++ usr.bin/strings/Makefile | 5 + usr.bin/strings/strings.1 | 96 + usr.bin/strings/strings.c | 216 + usr.bin/strip/Makefile | 11 + usr.bin/strip/strip.1 | 69 + usr.bin/strip/strip.c | 259 ++ usr.bin/su/Makefile | 11 + usr.bin/su/su.1 | 172 + usr.bin/su/su.c | 399 ++ usr.bin/systat/Makefile | 12 + usr.bin/systat/cmds.c | 192 + usr.bin/systat/cmdtab.c | 62 + usr.bin/systat/disks.c | 199 + usr.bin/systat/extern.h | 118 + usr.bin/systat/fetch.c | 54 + usr.bin/systat/iostat.c | 389 ++ usr.bin/systat/keyboard.c | 119 + usr.bin/systat/main.c | 286 ++ usr.bin/systat/mbufs.c | 163 + usr.bin/systat/netcmds.c | 308 ++ usr.bin/systat/netstat.c | 470 ++ usr.bin/systat/pigs.c | 245 + usr.bin/systat/swap.c | 257 ++ usr.bin/systat/systat.1 | 423 ++ usr.bin/systat/systat.h | 60 + usr.bin/systat/vmstat.c | 687 +++ usr.bin/tail/Makefile | 6 + usr.bin/tail/extern.h | 53 + usr.bin/tail/forward.c | 234 + usr.bin/tail/misc.c | 91 + usr.bin/tail/read.c | 198 + usr.bin/tail/reverse.c | 259 ++ usr.bin/tail/tail.1 | 165 + usr.bin/tail/tail.c | 302 ++ usr.bin/talk/Makefile | 9 + usr.bin/talk/ctl.c | 113 + usr.bin/talk/ctl_transact.c | 113 + usr.bin/talk/display.c | 190 + usr.bin/talk/get_addrs.c | 83 + usr.bin/talk/get_names.c | 118 + usr.bin/talk/init_disp.c | 149 + usr.bin/talk/invite.c | 188 + usr.bin/talk/io.c | 142 + usr.bin/talk/look_up.c | 115 + usr.bin/talk/msgs.c | 78 + usr.bin/talk/talk.1 | 129 + usr.bin/talk/talk.c | 74 + usr.bin/talk/talk.h | 58 + usr.bin/talk/talk_ctl.h | 43 + usr.bin/tcopy/Makefile | 5 + usr.bin/tcopy/pathnames.h | 36 + usr.bin/tcopy/tcopy.1 | 89 + usr.bin/tcopy/tcopy.c | 332 ++ usr.bin/tee/Makefile | 5 + usr.bin/tee/tee.1 | 88 + usr.bin/tee/tee.c | 168 + usr.bin/telnet/Makefile | 73 + usr.bin/telnet/README | 566 +++ usr.bin/telnet/authenc.c | 111 + usr.bin/telnet/commands.c | 2933 ++++++++++++ usr.bin/telnet/defines.h | 61 + usr.bin/telnet/externs.h | 481 ++ usr.bin/telnet/fdset.h | 49 + usr.bin/telnet/general.h | 45 + usr.bin/telnet/krb4-proto.h | 207 + usr.bin/telnet/main.c | 322 ++ usr.bin/telnet/network.c | 177 + usr.bin/telnet/ring.c | 362 ++ usr.bin/telnet/ring.h | 105 + usr.bin/telnet/sys_bsd.c | 1167 +++++ usr.bin/telnet/telnet.1 | 1360 ++++++ usr.bin/telnet/telnet.c | 2650 +++++++++++ usr.bin/telnet/terminal.c | 239 + usr.bin/telnet/tn3270.c | 411 ++ usr.bin/telnet/types.h | 52 + usr.bin/telnet/utilities.c | 939 ++++ usr.bin/tftp/Makefile | 6 + usr.bin/tftp/extern.h | 37 + usr.bin/tftp/main.c | 733 +++ usr.bin/tftp/tftp.1 | 173 + usr.bin/tftp/tftp.c | 453 ++ usr.bin/tftp/tftpsubs.c | 273 ++ usr.bin/tftp/tftpsubs.h | 48 + usr.bin/time/Makefile | 5 + usr.bin/time/time.1 | 99 + usr.bin/time/time.c | 140 + usr.bin/tip/Makefile | 52 + usr.bin/tip/acu.c | 196 + usr.bin/tip/aculib/biz22.c | 187 + usr.bin/tip/aculib/biz31.c | 248 + usr.bin/tip/aculib/courier.c | 380 ++ usr.bin/tip/aculib/df.c | 132 + usr.bin/tip/aculib/dn11.c | 142 + usr.bin/tip/aculib/hayes.c | 305 ++ usr.bin/tip/aculib/t3000.c | 408 ++ usr.bin/tip/aculib/v3451.c | 214 + usr.bin/tip/aculib/v831.c | 259 ++ usr.bin/tip/aculib/ventel.c | 251 ++ usr.bin/tip/acutab.c | 97 + usr.bin/tip/cmds.c | 888 ++++ usr.bin/tip/cmdtab.c | 64 + usr.bin/tip/cu.c | 132 + usr.bin/tip/hunt.c | 93 + usr.bin/tip/log.c | 86 + usr.bin/tip/partab.c | 58 + usr.bin/tip/pathnames.h | 44 + usr.bin/tip/remcap.c | 426 ++ usr.bin/tip/remote.c | 226 + usr.bin/tip/tip.1 | 451 ++ usr.bin/tip/tip.c | 599 +++ usr.bin/tip/tip.h | 278 ++ usr.bin/tip/tipout.c | 158 + usr.bin/tip/uucplock.c | 109 + usr.bin/tip/value.c | 353 ++ usr.bin/tip/vars.c | 112 + usr.bin/tn3270/Makefile | 9 + usr.bin/tn3270/Makefile.inc | 4 + usr.bin/tn3270/api/api_bsd.c | 281 ++ usr.bin/tn3270/api/api_exch.c | 429 ++ usr.bin/tn3270/api/api_exch.h | 161 + usr.bin/tn3270/api/apilib.c | 411 ++ usr.bin/tn3270/api/apilib.h | 44 + usr.bin/tn3270/api/asc_ebc.c | 110 + usr.bin/tn3270/api/asc_ebc.h | 51 + usr.bin/tn3270/api/astosc.c | 98 + usr.bin/tn3270/api/astosc.h | 58 + usr.bin/tn3270/api/dctype.c | 245 + usr.bin/tn3270/api/dctype.h | 54 + usr.bin/tn3270/api/disp_asc.c | 45 + usr.bin/tn3270/api/disp_asc.h | 43 + usr.bin/tn3270/api/ebc_disp.c | 106 + usr.bin/tn3270/api/ebc_disp.h | 38 + usr.bin/tn3270/ascii/default.map | 79 + usr.bin/tn3270/ascii/map3270.c | 934 ++++ usr.bin/tn3270/ascii/map3270.h | 41 + usr.bin/tn3270/ascii/mset.c | 410 ++ usr.bin/tn3270/ascii/state.h | 50 + usr.bin/tn3270/ascii/termin.c | 281 ++ usr.bin/tn3270/ctlr/3180.kbd | 182 + usr.bin/tn3270/ctlr/3270pc.kbd | 182 + usr.bin/tn3270/ctlr/api.c | 755 ++++ usr.bin/tn3270/ctlr/api.h | 403 ++ usr.bin/tn3270/ctlr/declare.h | 53 + usr.bin/tn3270/ctlr/externs.h | 66 + usr.bin/tn3270/ctlr/function.c | 47 + usr.bin/tn3270/ctlr/function.h | 166 + usr.bin/tn3270/ctlr/hostctlr.h | 222 + usr.bin/tn3270/ctlr/inbound.c | 1194 +++++ usr.bin/tn3270/ctlr/oia.c | 51 + usr.bin/tn3270/ctlr/oia.h | 190 + usr.bin/tn3270/ctlr/options.c | 181 + usr.bin/tn3270/ctlr/options.h | 41 + usr.bin/tn3270/ctlr/outbound.c | 605 +++ usr.bin/tn3270/ctlr/screen.h | 145 + usr.bin/tn3270/ctlr/scrnctlr.h | 48 + usr.bin/tn3270/ctlr/unix.kbd | 184 + usr.bin/tn3270/distribution/README | 99 + usr.bin/tn3270/distribution/arpa/makefile | 67 + usr.bin/tn3270/distribution/arpa/telnet.h | 191 + usr.bin/tn3270/distribution/makefile_4.2 | 268 ++ usr.bin/tn3270/distribution/sys_dos/makefile | 127 + usr.bin/tn3270/distribution/sys_dos/spint.h | 49 + usr.bin/tn3270/distribution/sys_dos/spintasm.asm | 252 ++ usr.bin/tn3270/distribution/sys_dos/spintc.c | 186 + usr.bin/tn3270/distribution/sys_dos/support.asm | 60 + usr.bin/tn3270/distribution/sys_dos/system.c | 140 + usr.bin/tn3270/distribution/sys_dos/termout.c | 514 +++ usr.bin/tn3270/distribution/sys_dos/termout.ext | 47 + usr.bin/tn3270/distribution/sys_dos/video.h | 75 + usr.bin/tn3270/distribution/telnet/Makefile_ultrix | 179 + usr.bin/tn3270/distribution/ultrix.curses | 46 + usr.bin/tn3270/distribution/utilities/adm3a.keys | 78 + usr.bin/tn3270/distribution/utilities/cross.c | 55 + usr.bin/tn3270/distribution/utilities/makefile | 121 + .../distribution/utilities/srccmd/tar/makefile | 8 + .../tn3270/distribution/utilities/srccmd/tar/tar.h | 19 + .../distribution/utilities/srccmd/tar/tarread.c | 208 + usr.bin/tn3270/distribution/utilities/tncomp.h | 51 + usr.bin/tn3270/distribution/utilities/tnrecv.c | 674 +++ usr.bin/tn3270/general/genbsubs.c | 125 + usr.bin/tn3270/general/general.h | 65 + usr.bin/tn3270/general/globals.c | 74 + usr.bin/tn3270/general/globals.h | 130 + usr.bin/tn3270/general/vaxbsubs.s | 101 + usr.bin/tn3270/mset/Makefile | 34 + usr.bin/tn3270/mset/map3270.5 | 341 ++ usr.bin/tn3270/mset/mset.1 | 188 + usr.bin/tn3270/sys_curses/system.c | 753 ++++ usr.bin/tn3270/sys_curses/telextrn.h | 71 + usr.bin/tn3270/sys_curses/terminal.h | 81 + usr.bin/tn3270/sys_curses/termout.c | 957 ++++ usr.bin/tn3270/telnet/Makefile | 87 + usr.bin/tn3270/tn3270/Makefile | 80 + usr.bin/tn3270/tn3270/tn3270.1 | 339 ++ usr.bin/tn3270/tools/Makefile | 5 + usr.bin/tn3270/tools/mkastods/Makefile | 9 + usr.bin/tn3270/tools/mkastods/mkastods.c | 77 + usr.bin/tn3270/tools/mkastosc/Makefile | 9 + usr.bin/tn3270/tools/mkastosc/mkastosc.c | 166 + usr.bin/tn3270/tools/mkdctype/Makefile | 9 + usr.bin/tn3270/tools/mkdctype/ectype.c | 313 ++ usr.bin/tn3270/tools/mkdctype/ectype.h | 52 + usr.bin/tn3270/tools/mkdctype/mkdctype.c | 99 + usr.bin/tn3270/tools/mkdstoas/Makefile | 9 + usr.bin/tn3270/tools/mkdstoas/mkdstoas.c | 78 + usr.bin/tn3270/tools/mkhits/Makefile | 9 + usr.bin/tn3270/tools/mkhits/dohits.c | 295 ++ usr.bin/tn3270/tools/mkhits/dohits.h | 56 + usr.bin/tn3270/tools/mkhits/mkhits.c | 147 + usr.bin/tn3270/tools/mkmake.y | 1097 +++++ usr.bin/tn3270/tools/prt3270.c | 620 +++ usr.bin/touch/Makefile | 5 + usr.bin/touch/touch.1 | 167 + usr.bin/touch/touch.c | 342 ++ usr.bin/tput/Makefile | 12 + usr.bin/tput/clear.sh | 37 + usr.bin/tput/tput.1 | 117 + usr.bin/tput/tput.c | 226 + usr.bin/tr/Makefile | 6 + usr.bin/tr/extern.h | 51 + usr.bin/tr/str.c | 342 ++ usr.bin/tr/tr.1 | 292 ++ usr.bin/tr/tr.c | 287 ++ usr.bin/true/Makefile | 5 + usr.bin/true/true.1 | 62 + usr.bin/true/true.c | 47 + usr.bin/tset/Makefile | 11 + usr.bin/tset/extern.h | 60 + usr.bin/tset/map.c | 263 ++ usr.bin/tset/misc.c | 98 + usr.bin/tset/set.c | 322 ++ usr.bin/tset/term.c | 155 + usr.bin/tset/tset.1 | 405 ++ usr.bin/tset/tset.c | 303 ++ usr.bin/tset/wrterm.c | 112 + usr.bin/tsort/Makefile | 5 + usr.bin/tsort/tsort.1 | 83 + usr.bin/tsort/tsort.c | 429 ++ usr.bin/tty/Makefile | 5 + usr.bin/tty/tty.1 | 78 + usr.bin/tty/tty.c | 69 + usr.bin/ul/Makefile | 7 + usr.bin/ul/ul.1 | 107 + usr.bin/ul/ul.c | 508 +++ usr.bin/uname/Makefile | 5 + usr.bin/uname/uname.1 | 97 + usr.bin/uname/uname.c | 162 + usr.bin/unexpand/Makefile | 6 + usr.bin/unexpand/unexpand.c | 131 + usr.bin/unifdef/Makefile | 5 + usr.bin/unifdef/unifdef.1 | 165 + usr.bin/unifdef/unifdef.c | 638 +++ usr.bin/uniq/Makefile | 5 + usr.bin/uniq/uniq.1 | 130 + usr.bin/uniq/uniq.c | 274 ++ usr.bin/unvis/Makefile | 5 + usr.bin/unvis/unvis.1 | 57 + usr.bin/unvis/unvis.c | 147 + usr.bin/users/Makefile | 5 + usr.bin/users/users.1 | 59 + usr.bin/users/users.c | 101 + usr.bin/uucp/acucntrl/Makefile | 10 + usr.bin/uucp/acucntrl/acucntrl.8 | 164 + usr.bin/uucp/acucntrl/acucntrl.c | 814 ++++ usr.bin/uucp/uupoll/Makefile | 10 + usr.bin/uucp/uupoll/uupoll.8 | 111 + usr.bin/uucp/uupoll/uupoll.c | 129 + usr.bin/uucp/uuq/Makefile | 9 + usr.bin/uucp/uuq/uuq.1 | 126 + usr.bin/uucp/uuq/uuq.c | 435 ++ usr.bin/uucp/uusend/Makefile | 6 + usr.bin/uucp/uusend/uusend.1 | 96 + usr.bin/uucp/uusend/uusend.c | 403 ++ usr.bin/uucp/uusnap/Makefile | 8 + usr.bin/uucp/uusnap/uusnap.8 | 80 + usr.bin/uucp/uusnap/uusnap.c | 348 ++ usr.bin/uudecode/Makefile | 6 + usr.bin/uudecode/uudecode.c | 187 + usr.bin/uuencode/Makefile | 8 + usr.bin/uuencode/uuencode.1 | 105 + usr.bin/uuencode/uuencode.c | 150 + usr.bin/uuencode/uuencode.format.5 | 102 + usr.bin/vacation/Makefile | 6 + usr.bin/vacation/vacation.1 | 171 + usr.bin/vacation/vacation.c | 420 ++ usr.bin/vgrind/Makefile | 21 + usr.bin/vgrind/RETEST/Makefile | 10 + usr.bin/vgrind/RETEST/retest.c | 105 + usr.bin/vgrind/extern.h | 65 + usr.bin/vgrind/pathnames.h | 36 + usr.bin/vgrind/regexp.c | 593 +++ usr.bin/vgrind/tmac.vgrind | 68 + usr.bin/vgrind/vfontedpr.c | 705 +++ usr.bin/vgrind/vgrind.1 | 224 + usr.bin/vgrind/vgrind.sh | 143 + usr.bin/vgrind/vgrindefs.5 | 158 + usr.bin/vgrind/vgrindefs.c | 326 ++ usr.bin/vgrind/vgrindefs.src | 146 + usr.bin/vis/Makefile | 6 + usr.bin/vis/foldit.c | 72 + usr.bin/vis/vis.1 | 124 + usr.bin/vis/vis.c | 173 + usr.bin/vmstat/Makefile | 11 + usr.bin/vmstat/names.c | 242 + usr.bin/vmstat/vmstat.8 | 206 + usr.bin/vmstat/vmstat.c | 873 ++++ usr.bin/w/Makefile | 14 + usr.bin/w/extern.h | 39 + usr.bin/w/pr_time.c | 104 + usr.bin/w/proc_compare.c | 120 + usr.bin/w/uptime.1 | 60 + usr.bin/w/w.1 | 141 + usr.bin/w/w.c | 426 ++ usr.bin/wall/Makefile | 8 + usr.bin/wall/ttymsg.c | 163 + usr.bin/wall/wall.1 | 63 + usr.bin/wall/wall.c | 201 + usr.bin/wc/Makefile | 5 + usr.bin/wc/wc.1 | 109 + usr.bin/wc/wc.c | 243 + usr.bin/what/Makefile | 5 + usr.bin/what/what.1 | 68 + usr.bin/what/what.c | 86 + usr.bin/whatis/Makefile | 7 + usr.bin/whatis/whatis.1 | 105 + usr.bin/whatis/whatis.c | 218 + usr.bin/whereis/Makefile | 5 + usr.bin/who/Makefile | 5 + usr.bin/who/who.1 | 105 + usr.bin/who/who.c | 135 + usr.bin/whois/Makefile | 5 + usr.bin/whois/whois.1 | 80 + usr.bin/whois/whois.c | 131 + usr.bin/window/:tt | 11 + usr.bin/window/:tty | 6 + usr.bin/window/:var | 2 + usr.bin/window/:ww | 19 + usr.bin/window/Makefile | 22 + usr.bin/window/README | 199 + usr.bin/window/alias.h | 52 + usr.bin/window/char.c | 150 + usr.bin/window/char.h | 61 + usr.bin/window/cmd.c | 300 ++ usr.bin/window/cmd1.c | 172 + usr.bin/window/cmd2.c | 154 + usr.bin/window/cmd3.c | 65 + usr.bin/window/cmd4.c | 56 + usr.bin/window/cmd5.c | 129 + usr.bin/window/cmd6.c | 110 + usr.bin/window/cmd7.c | 271 ++ usr.bin/window/compress.c | 899 ++++ usr.bin/window/context.c | 131 + usr.bin/window/context.h | 83 + usr.bin/window/defs.h | 71 + usr.bin/window/error.c | 95 + usr.bin/window/lcmd.c | 154 + usr.bin/window/lcmd.h | 61 + usr.bin/window/lcmd1.c | 429 ++ usr.bin/window/lcmd2.c | 397 ++ usr.bin/window/local.h | 51 + usr.bin/window/main.c | 202 + usr.bin/window/mloop.c | 84 + usr.bin/window/parser.h | 47 + usr.bin/window/parser1.c | 222 + usr.bin/window/parser2.c | 231 + usr.bin/window/parser3.c | 191 + usr.bin/window/parser4.c | 296 ++ usr.bin/window/parser5.c | 201 + usr.bin/window/scanner.c | 572 +++ usr.bin/window/startup.c | 92 + usr.bin/window/string.c | 153 + usr.bin/window/string.h | 65 + usr.bin/window/token.h | 83 + usr.bin/window/tt.h | 153 + usr.bin/window/ttf100.c | 69 + usr.bin/window/ttgeneric.c | 549 +++ usr.bin/window/tth19.c | 278 ++ usr.bin/window/tth29.c | 94 + usr.bin/window/ttinit.c | 119 + usr.bin/window/ttoutput.c | 146 + usr.bin/window/tttermcap.c | 117 + usr.bin/window/tttvi925.c | 64 + usr.bin/window/ttwyse60.c | 76 + usr.bin/window/ttwyse75.c | 76 + usr.bin/window/ttzapple.c | 483 ++ usr.bin/window/ttzentec.c | 66 + usr.bin/window/value.h | 53 + usr.bin/window/var.c | 157 + usr.bin/window/var.h | 58 + usr.bin/window/win.c | 370 ++ usr.bin/window/window.1 | 947 ++++ usr.bin/window/windowrc | 85 + usr.bin/window/ww.h | 321 ++ usr.bin/window/wwadd.c | 88 + usr.bin/window/wwalloc.c | 71 + usr.bin/window/wwbox.c | 66 + usr.bin/window/wwchild.c | 71 + usr.bin/window/wwclose.c | 59 + usr.bin/window/wwclreol.c | 95 + usr.bin/window/wwclreos.c | 55 + usr.bin/window/wwcursor.c | 92 + usr.bin/window/wwdata.c | 39 + usr.bin/window/wwdelchar.c | 123 + usr.bin/window/wwdelete.c | 139 + usr.bin/window/wwdelline.c | 88 + usr.bin/window/wwdump.c | 114 + usr.bin/window/wwend.c | 64 + usr.bin/window/wwenviron.c | 102 + usr.bin/window/wwerror.c | 69 + usr.bin/window/wwflush.c | 108 + usr.bin/window/wwframe.c | 249 ++ usr.bin/window/wwgets.c | 109 + usr.bin/window/wwinit.c | 388 ++ usr.bin/window/wwinschar.c | 130 + usr.bin/window/wwinsline.c | 88 + usr.bin/window/wwiomux.c | 203 + usr.bin/window/wwlabel.c | 96 + usr.bin/window/wwmisc.c | 67 + usr.bin/window/wwmove.c | 98 + usr.bin/window/wwopen.c | 188 + usr.bin/window/wwprintf.c | 57 + usr.bin/window/wwpty.c | 87 + usr.bin/window/wwputc.c | 48 + usr.bin/window/wwputs.c | 52 + usr.bin/window/wwredraw.c | 56 + usr.bin/window/wwredrawwin.c | 73 + usr.bin/window/wwrint.c | 91 + usr.bin/window/wwscroll.c | 234 + usr.bin/window/wwsize.c | 191 + usr.bin/window/wwspawn.c | 85 + usr.bin/window/wwsuspend.c | 56 + usr.bin/window/wwterminfo.c | 107 + usr.bin/window/wwtty.c | 180 + usr.bin/window/wwunframe.c | 76 + usr.bin/window/wwupdate.c | 271 ++ usr.bin/window/wwwrite.c | 298 ++ usr.bin/window/xx.c | 252 ++ usr.bin/window/xx.h | 58 + usr.bin/window/xxflush.c | 196 + usr.bin/write/Makefile | 7 + usr.bin/write/write.1 | 108 + usr.bin/write/write.c | 326 ++ usr.bin/xargs/Makefile | 5 + usr.bin/xargs/pathnames.h | 36 + usr.bin/xargs/xargs.1 | 161 + usr.bin/xargs/xargs.c | 325 ++ usr.bin/xinstall/Makefile | 12 + usr.bin/xinstall/install.1 | 124 + usr.bin/xinstall/pathnames.h | 36 + usr.bin/xinstall/xinstall.c | 358 ++ usr.bin/xstr/Makefile | 5 + usr.bin/xstr/pathnames.h | 36 + usr.bin/xstr/xstr.1 | 159 + usr.bin/xstr/xstr.c | 471 ++ usr.bin/yacc/ACKNOWLEDGEMENTS | 25 + usr.bin/yacc/Makefile | 12 + usr.bin/yacc/NEW_FEATURES | 46 + usr.bin/yacc/NOTES | 9 + usr.bin/yacc/README | 23 + usr.bin/yacc/closure.c | 295 ++ usr.bin/yacc/defs.h | 327 ++ usr.bin/yacc/error.c | 357 ++ usr.bin/yacc/lalr.c | 678 +++ usr.bin/yacc/lr0.c | 637 +++ usr.bin/yacc/main.c | 423 ++ usr.bin/yacc/mkpar.c | 395 ++ usr.bin/yacc/output.c | 1250 ++++++ usr.bin/yacc/reader.c | 1810 ++++++++ usr.bin/yacc/skeleton.c | 346 ++ usr.bin/yacc/symtab.c | 158 + usr.bin/yacc/test/error.output | 27 + usr.bin/yacc/test/error.tab.c | 275 ++ usr.bin/yacc/test/error.tab.h | 0 usr.bin/yacc/test/error.y | 6 + usr.bin/yacc/test/ftp.output | 1625 +++++++ usr.bin/yacc/test/ftp.tab.c | 1743 ++++++++ usr.bin/yacc/test/ftp.tab.h | 63 + usr.bin/yacc/test/ftp.y | 1180 +++++ usr.bin/yacc/verbose.c | 366 ++ usr.bin/yacc/warshall.c | 122 + usr.bin/yacc/yacc.1 | 145 + usr.bin/yacc/yyfix.1 | 112 + usr.bin/yacc/yyfix.sh | 71 + usr.bin/yes/Makefile | 5 + usr.bin/yes/yes.1 | 54 + usr.bin/yes/yes.c | 53 + 1082 files changed, 223656 insertions(+) create mode 100644 usr.bin/Makefile create mode 100644 usr.bin/Makefile.inc create mode 100644 usr.bin/apply/Makefile create mode 100644 usr.bin/apply/apply.1 create mode 100644 usr.bin/apply/apply.c create mode 100644 usr.bin/apropos/Makefile create mode 100644 usr.bin/apropos/apropos.1 create mode 100644 usr.bin/apropos/apropos.c create mode 100644 usr.bin/ar/Makefile create mode 100644 usr.bin/ar/append.c create mode 100644 usr.bin/ar/ar.1 create mode 100644 usr.bin/ar/ar.5.5 create mode 100644 usr.bin/ar/ar.c create mode 100644 usr.bin/ar/archive.c create mode 100644 usr.bin/ar/archive.h create mode 100644 usr.bin/ar/contents.c create mode 100644 usr.bin/ar/delete.c create mode 100644 usr.bin/ar/extern.h create mode 100644 usr.bin/ar/extract.c create mode 100644 usr.bin/ar/misc.c create mode 100644 usr.bin/ar/move.c create mode 100644 usr.bin/ar/pathnames.h create mode 100644 usr.bin/ar/print.c create mode 100644 usr.bin/ar/replace.c create mode 100644 usr.bin/banner/Makefile create mode 100644 usr.bin/banner/banner.6 create mode 100644 usr.bin/banner/banner.c create mode 100644 usr.bin/basename/Makefile create mode 100644 usr.bin/basename/basename.1 create mode 100644 usr.bin/basename/basename.c create mode 100644 usr.bin/bdes/Makefile create mode 100644 usr.bin/bdes/bdes.1 create mode 100644 usr.bin/bdes/bdes.c create mode 100644 usr.bin/bdes/bdes.ps create mode 100644 usr.bin/biff/Makefile create mode 100644 usr.bin/biff/biff.1 create mode 100644 usr.bin/biff/biff.c create mode 100644 usr.bin/cal/Makefile create mode 100644 usr.bin/cal/README create mode 100644 usr.bin/cal/cal.1 create mode 100644 usr.bin/cal/cal.c create mode 100644 usr.bin/calendar/Makefile create mode 100644 usr.bin/calendar/calendar.1 create mode 100644 usr.bin/calendar/calendar.c create mode 100644 usr.bin/calendar/calendars/calendar.birthday create mode 100644 usr.bin/calendar/calendars/calendar.christian create mode 100644 usr.bin/calendar/calendars/calendar.computer create mode 100644 usr.bin/calendar/calendars/calendar.history create mode 100644 usr.bin/calendar/calendars/calendar.holiday create mode 100644 usr.bin/calendar/calendars/calendar.judaic create mode 100644 usr.bin/calendar/calendars/calendar.music create mode 100644 usr.bin/calendar/calendars/calendar.usholiday create mode 100644 usr.bin/calendar/pathnames.h create mode 100644 usr.bin/cap_mkdb/Makefile create mode 100644 usr.bin/cap_mkdb/cap_mkdb.1 create mode 100644 usr.bin/cap_mkdb/cap_mkdb.c create mode 100644 usr.bin/checknr/Makefile create mode 100644 usr.bin/checknr/checknr.1 create mode 100644 usr.bin/checknr/checknr.c create mode 100644 usr.bin/chflags/Makefile create mode 100644 usr.bin/chflags/chflags.1 create mode 100644 usr.bin/chflags/chflags.c create mode 100644 usr.bin/chpass/Makefile create mode 100644 usr.bin/chpass/chpass.1 create mode 100644 usr.bin/chpass/chpass.c create mode 100644 usr.bin/chpass/chpass.h create mode 100644 usr.bin/chpass/edit.c create mode 100644 usr.bin/chpass/field.c create mode 100644 usr.bin/chpass/pathnames.h create mode 100644 usr.bin/chpass/pw_copy.c create mode 100644 usr.bin/chpass/pw_copy.h create mode 100644 usr.bin/chpass/table.c create mode 100644 usr.bin/chpass/util.c create mode 100644 usr.bin/cksum/Makefile create mode 100644 usr.bin/cksum/cksum.1 create mode 100644 usr.bin/cksum/cksum.c create mode 100644 usr.bin/cksum/crc.c create mode 100644 usr.bin/cksum/extern.h create mode 100644 usr.bin/cksum/print.c create mode 100644 usr.bin/cksum/sum1.c create mode 100644 usr.bin/cksum/sum2.c create mode 100644 usr.bin/cmp/Makefile create mode 100644 usr.bin/cmp/cmp.1 create mode 100644 usr.bin/cmp/cmp.c create mode 100644 usr.bin/cmp/extern.h create mode 100644 usr.bin/cmp/misc.c create mode 100644 usr.bin/cmp/regular.c create mode 100644 usr.bin/cmp/special.c create mode 100644 usr.bin/col/Makefile create mode 100644 usr.bin/col/README create mode 100644 usr.bin/col/col.1 create mode 100644 usr.bin/col/col.c create mode 100644 usr.bin/colcrt/Makefile create mode 100644 usr.bin/colcrt/colcrt.1 create mode 100644 usr.bin/colcrt/colcrt.c create mode 100644 usr.bin/colrm/Makefile create mode 100644 usr.bin/colrm/colrm.1 create mode 100644 usr.bin/colrm/colrm.c create mode 100644 usr.bin/column/Makefile create mode 100644 usr.bin/column/column.1 create mode 100644 usr.bin/column/column.c create mode 100644 usr.bin/comm/Makefile create mode 100644 usr.bin/comm/comm.1 create mode 100644 usr.bin/comm/comm.c create mode 100644 usr.bin/compress/Makefile create mode 100644 usr.bin/compress/compress.1 create mode 100644 usr.bin/compress/compress.c create mode 100644 usr.bin/compress/doc/NOTES create mode 100644 usr.bin/compress/doc/README create mode 100644 usr.bin/compress/doc/revision.log create mode 100644 usr.bin/compress/zcat.sh create mode 100644 usr.bin/compress/zopen.3 create mode 100644 usr.bin/compress/zopen.c create mode 100644 usr.bin/cpp/Makefile create mode 100644 usr.bin/cpp/cpp.notraditional.sh create mode 100644 usr.bin/cpp/cpp.sh create mode 100644 usr.bin/ctags/C.c create mode 100644 usr.bin/ctags/Makefile create mode 100644 usr.bin/ctags/ctags.1 create mode 100644 usr.bin/ctags/ctags.c create mode 100644 usr.bin/ctags/ctags.h create mode 100644 usr.bin/ctags/fortran.c create mode 100644 usr.bin/ctags/lisp.c create mode 100644 usr.bin/ctags/print.c create mode 100644 usr.bin/ctags/test/ctags.test create mode 100644 usr.bin/ctags/tree.c create mode 100644 usr.bin/ctags/yacc.c create mode 100644 usr.bin/cut/Makefile create mode 100644 usr.bin/cut/cut.1 create mode 100644 usr.bin/cut/cut.c create mode 100644 usr.bin/diff/diff/diff.1 create mode 100644 usr.bin/diff/diff3/diff3.1 create mode 100644 usr.bin/dirname/Makefile create mode 100644 usr.bin/dirname/dirname.c create mode 100644 usr.bin/du/Makefile create mode 100644 usr.bin/du/du.1 create mode 100644 usr.bin/du/du.c create mode 100644 usr.bin/env/Makefile create mode 100644 usr.bin/env/env.c create mode 100644 usr.bin/error/Makefile create mode 100644 usr.bin/error/error.1 create mode 100644 usr.bin/error/error.h create mode 100644 usr.bin/error/filter.c create mode 100644 usr.bin/error/input.c create mode 100644 usr.bin/error/main.c create mode 100644 usr.bin/error/pathnames.h create mode 100644 usr.bin/error/pi.c create mode 100644 usr.bin/error/subr.c create mode 100644 usr.bin/error/touch.c create mode 100644 usr.bin/expand/Makefile create mode 100644 usr.bin/expand/expand.1 create mode 100644 usr.bin/expand/expand.c create mode 100644 usr.bin/false/Makefile create mode 100644 usr.bin/false/false.1 create mode 100644 usr.bin/false/false.c create mode 100644 usr.bin/find/Makefile create mode 100644 usr.bin/find/extern.h create mode 100644 usr.bin/find/find.1 create mode 100644 usr.bin/find/find.c create mode 100644 usr.bin/find/find.h create mode 100644 usr.bin/find/function.c create mode 100644 usr.bin/find/ls.c create mode 100644 usr.bin/find/main.c create mode 100644 usr.bin/find/misc.c create mode 100644 usr.bin/find/operator.c create mode 100644 usr.bin/find/option.c create mode 100644 usr.bin/finger/Makefile create mode 100644 usr.bin/finger/extern.h create mode 100644 usr.bin/finger/finger.1 create mode 100644 usr.bin/finger/finger.c create mode 100644 usr.bin/finger/finger.h create mode 100644 usr.bin/finger/lprint.c create mode 100644 usr.bin/finger/net.c create mode 100644 usr.bin/finger/sprint.c create mode 100644 usr.bin/finger/util.c create mode 100644 usr.bin/fmt/Makefile create mode 100644 usr.bin/fmt/fmt.1 create mode 100644 usr.bin/fmt/fmt.c create mode 100644 usr.bin/fold/Makefile create mode 100644 usr.bin/fold/fold.1 create mode 100644 usr.bin/fold/fold.c create mode 100644 usr.bin/fpr/Makefile create mode 100644 usr.bin/fpr/fpr.1 create mode 100644 usr.bin/fpr/fpr.c create mode 100644 usr.bin/from/Makefile create mode 100644 usr.bin/from/from.1 create mode 100644 usr.bin/from/from.c create mode 100644 usr.bin/fsplit/Makefile create mode 100644 usr.bin/fsplit/fsplit.1 create mode 100644 usr.bin/fsplit/fsplit.c create mode 100644 usr.bin/fstat/Makefile create mode 100644 usr.bin/fstat/fstat.1 create mode 100644 usr.bin/fstat/fstat.c create mode 100644 usr.bin/ftp/Makefile create mode 100644 usr.bin/ftp/cmds.c create mode 100644 usr.bin/ftp/cmdtab.c create mode 100644 usr.bin/ftp/domacro.c create mode 100644 usr.bin/ftp/extern.h create mode 100644 usr.bin/ftp/ftp.1 create mode 100644 usr.bin/ftp/ftp.c create mode 100644 usr.bin/ftp/ftp_var.h create mode 100644 usr.bin/ftp/main.c create mode 100644 usr.bin/ftp/pathnames.h create mode 100644 usr.bin/ftp/ruserpass.c create mode 100644 usr.bin/gcore/Makefile create mode 100644 usr.bin/gcore/extern.h create mode 100644 usr.bin/gcore/gcore.1 create mode 100644 usr.bin/gcore/gcore.c create mode 100644 usr.bin/gcore/md-nop.c create mode 100644 usr.bin/gcore/md-sparc.c create mode 100644 usr.bin/gprof/Makefile create mode 100644 usr.bin/gprof/PSD.doc/Makefile create mode 100644 usr.bin/gprof/PSD.doc/abstract.me create mode 100644 usr.bin/gprof/PSD.doc/gathering.me create mode 100644 usr.bin/gprof/PSD.doc/header.me create mode 100644 usr.bin/gprof/PSD.doc/intro.me create mode 100644 usr.bin/gprof/PSD.doc/postp.me create mode 100644 usr.bin/gprof/PSD.doc/postp1.pic create mode 100644 usr.bin/gprof/PSD.doc/postp2.pic create mode 100644 usr.bin/gprof/PSD.doc/postp3.pic create mode 100644 usr.bin/gprof/PSD.doc/pres1.pic create mode 100644 usr.bin/gprof/PSD.doc/pres2.pic create mode 100644 usr.bin/gprof/PSD.doc/present.me create mode 100644 usr.bin/gprof/PSD.doc/profiling.me create mode 100644 usr.bin/gprof/PSD.doc/refs.me create mode 100644 usr.bin/gprof/arcs.c create mode 100644 usr.bin/gprof/dfn.c create mode 100644 usr.bin/gprof/gprof.1 create mode 100644 usr.bin/gprof/gprof.c create mode 100644 usr.bin/gprof/gprof.callg create mode 100644 usr.bin/gprof/gprof.flat create mode 100644 usr.bin/gprof/gprof.h create mode 100644 usr.bin/gprof/hertz.c create mode 100644 usr.bin/gprof/hp300.c create mode 100644 usr.bin/gprof/hp300.h create mode 100644 usr.bin/gprof/i386.c create mode 100644 usr.bin/gprof/i386.h create mode 100644 usr.bin/gprof/lookup.c create mode 100644 usr.bin/gprof/mips.c create mode 100644 usr.bin/gprof/mips.h create mode 100644 usr.bin/gprof/pathnames.h create mode 100644 usr.bin/gprof/printgprof.c create mode 100644 usr.bin/gprof/printlist.c create mode 100644 usr.bin/gprof/sparc.c create mode 100644 usr.bin/gprof/sparc.h create mode 100644 usr.bin/gprof/tahoe.c create mode 100644 usr.bin/gprof/tahoe.h create mode 100644 usr.bin/gprof/vax.c create mode 100644 usr.bin/gprof/vax.h create mode 100644 usr.bin/grep/egrep/Makefile create mode 100644 usr.bin/grep/egrep/egrep.c create mode 100644 usr.bin/grep/egrep/grep.1 create mode 100644 usr.bin/grep/egrep/pathnames.h create mode 100644 usr.bin/head/Makefile create mode 100644 usr.bin/head/head.1 create mode 100644 usr.bin/head/head.c create mode 100644 usr.bin/hexdump/Makefile create mode 100644 usr.bin/hexdump/conv.c create mode 100644 usr.bin/hexdump/display.c create mode 100644 usr.bin/hexdump/hexdump.1 create mode 100644 usr.bin/hexdump/hexdump.c create mode 100644 usr.bin/hexdump/hexdump.h create mode 100644 usr.bin/hexdump/hexsyntax.c create mode 100644 usr.bin/hexdump/od.1 create mode 100644 usr.bin/hexdump/odsyntax.c create mode 100644 usr.bin/hexdump/parse.c create mode 100644 usr.bin/id/Makefile create mode 100644 usr.bin/id/groups.1 create mode 100644 usr.bin/id/groups.sh create mode 100644 usr.bin/id/id.1 create mode 100644 usr.bin/id/id.c create mode 100644 usr.bin/id/whoami.1 create mode 100644 usr.bin/id/whoami.sh create mode 100644 usr.bin/indent/Makefile create mode 100644 usr.bin/indent/README create mode 100644 usr.bin/indent/args.c create mode 100644 usr.bin/indent/indent.1 create mode 100644 usr.bin/indent/indent.c create mode 100644 usr.bin/indent/indent_codes.h create mode 100644 usr.bin/indent/indent_globs.h create mode 100644 usr.bin/indent/io.c create mode 100644 usr.bin/indent/lexi.c create mode 100644 usr.bin/indent/parse.c create mode 100644 usr.bin/indent/pr_comment.c create mode 100644 usr.bin/join/Makefile create mode 100644 usr.bin/join/join.1 create mode 100644 usr.bin/join/join.c create mode 100644 usr.bin/jot/Makefile create mode 100644 usr.bin/jot/jot.1 create mode 100644 usr.bin/jot/jot.c create mode 100644 usr.bin/kdump/Makefile create mode 100644 usr.bin/kdump/kdump.1 create mode 100644 usr.bin/kdump/kdump.c create mode 100644 usr.bin/kdump/mkioctls create mode 100644 usr.bin/ktrace/Makefile create mode 100644 usr.bin/ktrace/ktrace.1 create mode 100644 usr.bin/ktrace/ktrace.c create mode 100644 usr.bin/ktrace/ktrace.h create mode 100644 usr.bin/ktrace/subr.c create mode 100644 usr.bin/lam/Makefile create mode 100644 usr.bin/lam/lam.1 create mode 100644 usr.bin/lam/lam.c create mode 100644 usr.bin/last/Makefile create mode 100644 usr.bin/last/last.1 create mode 100644 usr.bin/last/last.c create mode 100644 usr.bin/lastcomm/Makefile create mode 100644 usr.bin/lastcomm/lastcomm.1 create mode 100644 usr.bin/lastcomm/lastcomm.c create mode 100644 usr.bin/lastcomm/pathnames.h create mode 100644 usr.bin/ld/Makefile create mode 100644 usr.bin/ld/cplus-dem.c create mode 100644 usr.bin/ld/ld.c create mode 100644 usr.bin/ld/symseg.h create mode 100644 usr.bin/leave/Makefile create mode 100644 usr.bin/leave/leave.1 create mode 100644 usr.bin/leave/leave.c create mode 100644 usr.bin/locate/Makefile create mode 100644 usr.bin/locate/bigram/Makefile create mode 100644 usr.bin/locate/bigram/locate.bigram.c create mode 100644 usr.bin/locate/code/Makefile create mode 100644 usr.bin/locate/code/locate.code.c create mode 100644 usr.bin/locate/locate/Makefile create mode 100644 usr.bin/locate/locate/locate.1 create mode 100644 usr.bin/locate/locate/locate.c create mode 100644 usr.bin/locate/locate/locate.h create mode 100644 usr.bin/locate/locate/pathnames.h create mode 100644 usr.bin/locate/locate/updatedb.csh create mode 100644 usr.bin/lock/Makefile create mode 100644 usr.bin/lock/lock.1 create mode 100644 usr.bin/lock/lock.c create mode 100644 usr.bin/logger/Makefile create mode 100644 usr.bin/logger/logger.1 create mode 100644 usr.bin/logger/logger.c create mode 100644 usr.bin/login/Makefile create mode 100644 usr.bin/login/klogin.c create mode 100644 usr.bin/login/login.1 create mode 100644 usr.bin/login/login.c create mode 100644 usr.bin/login/pathnames.h create mode 100644 usr.bin/logname/Makefile create mode 100644 usr.bin/logname/logname.1 create mode 100644 usr.bin/logname/logname.c create mode 100644 usr.bin/look/Makefile create mode 100644 usr.bin/look/look.1 create mode 100644 usr.bin/look/look.c create mode 100644 usr.bin/look/pathnames.h create mode 100644 usr.bin/lorder/Makefile create mode 100644 usr.bin/lorder/lorder.1 create mode 100644 usr.bin/lorder/lorder.sh create mode 100644 usr.bin/m4/serv.c create mode 100644 usr.bin/mail/Makefile create mode 100644 usr.bin/mail/USD.doc/Makefile create mode 100644 usr.bin/mail/USD.doc/mail0.nr create mode 100644 usr.bin/mail/USD.doc/mail1.nr create mode 100644 usr.bin/mail/USD.doc/mail2.nr create mode 100644 usr.bin/mail/USD.doc/mail3.nr create mode 100644 usr.bin/mail/USD.doc/mail4.nr create mode 100644 usr.bin/mail/USD.doc/mail5.nr create mode 100644 usr.bin/mail/USD.doc/mail6.nr create mode 100644 usr.bin/mail/USD.doc/mail7.nr create mode 100644 usr.bin/mail/USD.doc/mail8.nr create mode 100644 usr.bin/mail/USD.doc/mail9.nr create mode 100644 usr.bin/mail/USD.doc/maila.nr create mode 100644 usr.bin/mail/aux.c create mode 100644 usr.bin/mail/cmd1.c create mode 100644 usr.bin/mail/cmd2.c create mode 100644 usr.bin/mail/cmd3.c create mode 100644 usr.bin/mail/cmdtab.c create mode 100644 usr.bin/mail/collect.c create mode 100644 usr.bin/mail/def.h create mode 100644 usr.bin/mail/edit.c create mode 100644 usr.bin/mail/extern.h create mode 100644 usr.bin/mail/fio.c create mode 100644 usr.bin/mail/getname.c create mode 100644 usr.bin/mail/glob.h create mode 100644 usr.bin/mail/head.c create mode 100644 usr.bin/mail/lex.c create mode 100644 usr.bin/mail/list.c create mode 100644 usr.bin/mail/mail.1 create mode 100644 usr.bin/mail/main.c create mode 100644 usr.bin/mail/misc/mail.help create mode 100644 usr.bin/mail/misc/mail.rc create mode 100644 usr.bin/mail/misc/mail.tildehelp create mode 100644 usr.bin/mail/names.c create mode 100644 usr.bin/mail/pathnames.h create mode 100644 usr.bin/mail/popen.c create mode 100644 usr.bin/mail/quit.c create mode 100644 usr.bin/mail/rcv.h create mode 100644 usr.bin/mail/send.c create mode 100644 usr.bin/mail/strings.c create mode 100644 usr.bin/mail/temp.c create mode 100644 usr.bin/mail/tty.c create mode 100644 usr.bin/mail/v7.local.c create mode 100644 usr.bin/mail/vars.c create mode 100644 usr.bin/mail/version.c create mode 100644 usr.bin/make/Makefile.dist create mode 100644 usr.bin/make/bit.h create mode 100644 usr.bin/man/Makefile create mode 100644 usr.bin/man/config.c create mode 100644 usr.bin/man/config.h create mode 100644 usr.bin/man/man.1 create mode 100644 usr.bin/man/man.c create mode 100644 usr.bin/man/man.conf create mode 100644 usr.bin/man/man.conf.5 create mode 100644 usr.bin/man/pathnames.h create mode 100644 usr.bin/mesg/Makefile create mode 100644 usr.bin/mesg/mesg.1 create mode 100644 usr.bin/mesg/mesg.c create mode 100644 usr.bin/mkdep/Makefile create mode 100644 usr.bin/mkdep/mkdep.1 create mode 100644 usr.bin/mkdep/mkdep.append create mode 100644 usr.bin/mkdep/mkdep.gcc.sh create mode 100644 usr.bin/mkdep/mkdep.old.compiler create mode 100644 usr.bin/mkdep/mkdep.sh create mode 100644 usr.bin/mkdep/mkdep.ultrix create mode 100644 usr.bin/mkfifo/Makefile create mode 100644 usr.bin/mkfifo/mkfifo.1 create mode 100644 usr.bin/mkfifo/mkfifo.c create mode 100644 usr.bin/mklocale/Japanese create mode 100644 usr.bin/mklocale/Makefile create mode 100644 usr.bin/mklocale/POSIX create mode 100644 usr.bin/mklocale/ldef.h create mode 100644 usr.bin/mklocale/lex.l create mode 100644 usr.bin/mklocale/mklocale.1 create mode 100644 usr.bin/mklocale/yacc.y create mode 100644 usr.bin/mkstr/Makefile create mode 100644 usr.bin/mkstr/mkstr.1 create mode 100644 usr.bin/mkstr/mkstr.c create mode 100644 usr.bin/more/Makefile create mode 100644 usr.bin/more/ch.c create mode 100644 usr.bin/more/command.c create mode 100644 usr.bin/more/decode.c create mode 100644 usr.bin/more/help.c create mode 100644 usr.bin/more/input.c create mode 100644 usr.bin/more/less.h create mode 100644 usr.bin/more/line.c create mode 100644 usr.bin/more/linenum.c create mode 100644 usr.bin/more/main.c create mode 100644 usr.bin/more/more.1 create mode 100644 usr.bin/more/more.help create mode 100644 usr.bin/more/option.c create mode 100644 usr.bin/more/os.c create mode 100644 usr.bin/more/output.c create mode 100644 usr.bin/more/pathnames.h create mode 100644 usr.bin/more/position.c create mode 100644 usr.bin/more/prim.c create mode 100644 usr.bin/more/screen.c create mode 100644 usr.bin/more/signal.c create mode 100644 usr.bin/more/tags.c create mode 100644 usr.bin/more/ttyin.c create mode 100644 usr.bin/msgs/Makefile create mode 100644 usr.bin/msgs/msgs.1 create mode 100644 usr.bin/msgs/msgs.c create mode 100644 usr.bin/msgs/pathnames.h create mode 100644 usr.bin/mt/Makefile create mode 100644 usr.bin/mt/mt.1 create mode 100644 usr.bin/mt/mt.c create mode 100644 usr.bin/netstat/Makefile create mode 100644 usr.bin/netstat/if.c create mode 100644 usr.bin/netstat/inet.c create mode 100644 usr.bin/netstat/iso.c create mode 100644 usr.bin/netstat/main.c create mode 100644 usr.bin/netstat/mbuf.c create mode 100644 usr.bin/netstat/mroute.c create mode 100644 usr.bin/netstat/netstat.1 create mode 100644 usr.bin/netstat/netstat.h create mode 100644 usr.bin/netstat/ns.c create mode 100644 usr.bin/netstat/route.c create mode 100644 usr.bin/netstat/unix.c create mode 100644 usr.bin/nfsstat/Makefile create mode 100644 usr.bin/nfsstat/nfsstat.1 create mode 100644 usr.bin/nfsstat/nfsstat.c create mode 100644 usr.bin/nice/Makefile create mode 100644 usr.bin/nice/nice.1 create mode 100644 usr.bin/nice/nice.c create mode 100644 usr.bin/nm/Makefile create mode 100644 usr.bin/nm/nm.1 create mode 100644 usr.bin/nm/nm.c create mode 100644 usr.bin/nohup/Makefile create mode 100644 usr.bin/nohup/nohup.1 create mode 100644 usr.bin/nohup/nohup.c create mode 100644 usr.bin/pagesize/Makefile create mode 100644 usr.bin/pagesize/pagesize.1 create mode 100644 usr.bin/pagesize/pagesize.sh create mode 100644 usr.bin/passwd/Makefile create mode 100644 usr.bin/passwd/extern.h create mode 100644 usr.bin/passwd/kpasswd_proto.h create mode 100644 usr.bin/passwd/krb_passwd.c create mode 100644 usr.bin/passwd/local_passwd.c create mode 100644 usr.bin/passwd/passwd.1 create mode 100644 usr.bin/passwd/passwd.c create mode 100644 usr.bin/paste/Makefile create mode 100644 usr.bin/paste/paste.1 create mode 100644 usr.bin/paste/paste.c create mode 100644 usr.bin/patch/EXTERN.h create mode 100644 usr.bin/patch/INTERN.h create mode 100644 usr.bin/patch/config.h create mode 100644 usr.bin/patch/patchlevel.h create mode 100644 usr.bin/patch/version.c create mode 100644 usr.bin/patch/version.h create mode 100644 usr.bin/pr/Makefile create mode 100644 usr.bin/pr/egetopt.c create mode 100644 usr.bin/pr/extern.h create mode 100644 usr.bin/pr/pr.1 create mode 100644 usr.bin/pr/pr.c create mode 100644 usr.bin/pr/pr.h create mode 100644 usr.bin/printenv/Makefile create mode 100644 usr.bin/printenv/printenv.1 create mode 100644 usr.bin/printenv/printenv.c create mode 100644 usr.bin/printf/Makefile create mode 100644 usr.bin/printf/printf.1 create mode 100644 usr.bin/printf/printf.c create mode 100644 usr.bin/quota/Makefile create mode 100644 usr.bin/quota/quota.1 create mode 100644 usr.bin/quota/quota.c create mode 100644 usr.bin/ranlib/Makefile create mode 100644 usr.bin/ranlib/build.c create mode 100644 usr.bin/ranlib/misc.c create mode 100644 usr.bin/ranlib/pathnames.h create mode 100644 usr.bin/ranlib/ranlib.1 create mode 100644 usr.bin/ranlib/ranlib.5.5 create mode 100644 usr.bin/ranlib/ranlib.c create mode 100644 usr.bin/ranlib/touch.c create mode 100644 usr.bin/rdist/Makefile create mode 100644 usr.bin/rdist/cron.entry create mode 100644 usr.bin/rdist/defs.h create mode 100644 usr.bin/rdist/docmd.c create mode 100644 usr.bin/rdist/expand.c create mode 100644 usr.bin/rdist/gram.y create mode 100644 usr.bin/rdist/lookup.c create mode 100644 usr.bin/rdist/main.c create mode 100644 usr.bin/rdist/pathnames.h create mode 100644 usr.bin/rdist/rdist.1 create mode 100644 usr.bin/rdist/server.c create mode 100644 usr.bin/renice/Makefile create mode 100644 usr.bin/renice/renice.8 create mode 100644 usr.bin/renice/renice.c create mode 100644 usr.bin/rev/Makefile create mode 100644 usr.bin/rev/rev.1 create mode 100644 usr.bin/rev/rev.c create mode 100644 usr.bin/rlogin/Makefile create mode 100644 usr.bin/rlogin/des_rw.c create mode 100644 usr.bin/rlogin/kcmd.c create mode 100644 usr.bin/rlogin/krb.h create mode 100644 usr.bin/rlogin/krcmd.c create mode 100644 usr.bin/rlogin/rlogin.1 create mode 100644 usr.bin/rlogin/rlogin.c create mode 100644 usr.bin/rs/Makefile create mode 100644 usr.bin/rs/rs.1 create mode 100644 usr.bin/rs/rs.c create mode 100644 usr.bin/rsh/Makefile create mode 100644 usr.bin/rsh/pathnames.h create mode 100644 usr.bin/rsh/rsh.1 create mode 100644 usr.bin/rsh/rsh.c create mode 100644 usr.bin/ruptime/Makefile create mode 100644 usr.bin/ruptime/ruptime.1 create mode 100644 usr.bin/ruptime/ruptime.c create mode 100644 usr.bin/rwho/Makefile create mode 100644 usr.bin/rwho/rwho.1 create mode 100644 usr.bin/rwho/rwho.c create mode 100644 usr.bin/sccs/Makefile create mode 100644 usr.bin/sccs/PSD.doc/Makefile create mode 100644 usr.bin/sccs/PSD.doc/sccs.me create mode 100644 usr.bin/sccs/PSD.doc/spell.ok create mode 100644 usr.bin/sccs/pathnames.h create mode 100644 usr.bin/sccs/sccs.1 create mode 100644 usr.bin/sccs/sccs.c create mode 100644 usr.bin/script/Makefile create mode 100644 usr.bin/script/script.1 create mode 100644 usr.bin/script/script.c create mode 100644 usr.bin/sed/Makefile create mode 100644 usr.bin/sed/POSIX create mode 100644 usr.bin/sed/TEST/hanoi.sed create mode 100644 usr.bin/sed/TEST/math.sed create mode 100644 usr.bin/sed/TEST/sed.test create mode 100644 usr.bin/sed/compile.c create mode 100644 usr.bin/sed/defs.h create mode 100644 usr.bin/sed/extern.h create mode 100644 usr.bin/sed/main.c create mode 100644 usr.bin/sed/misc.c create mode 100644 usr.bin/sed/process.c create mode 100644 usr.bin/sed/sed.1 create mode 100644 usr.bin/shar/Makefile create mode 100644 usr.bin/shar/shar.1 create mode 100644 usr.bin/shar/shar.sh create mode 100644 usr.bin/showmount/Makefile create mode 100644 usr.bin/showmount/showmount.8 create mode 100644 usr.bin/showmount/showmount.c create mode 100644 usr.bin/size/Makefile create mode 100644 usr.bin/size/size.1 create mode 100644 usr.bin/size/size.c create mode 100644 usr.bin/soelim/Makefile create mode 100644 usr.bin/soelim/soelim.1 create mode 100644 usr.bin/soelim/soelim.c create mode 100644 usr.bin/split/Makefile create mode 100644 usr.bin/split/split.1 create mode 100644 usr.bin/split/split.c create mode 100644 usr.bin/strings/Makefile create mode 100644 usr.bin/strings/strings.1 create mode 100644 usr.bin/strings/strings.c create mode 100644 usr.bin/strip/Makefile create mode 100644 usr.bin/strip/strip.1 create mode 100644 usr.bin/strip/strip.c create mode 100644 usr.bin/su/Makefile create mode 100644 usr.bin/su/su.1 create mode 100644 usr.bin/su/su.c create mode 100644 usr.bin/systat/Makefile create mode 100644 usr.bin/systat/cmds.c create mode 100644 usr.bin/systat/cmdtab.c create mode 100644 usr.bin/systat/disks.c create mode 100644 usr.bin/systat/extern.h create mode 100644 usr.bin/systat/fetch.c create mode 100644 usr.bin/systat/iostat.c create mode 100644 usr.bin/systat/keyboard.c create mode 100644 usr.bin/systat/main.c create mode 100644 usr.bin/systat/mbufs.c create mode 100644 usr.bin/systat/netcmds.c create mode 100644 usr.bin/systat/netstat.c create mode 100644 usr.bin/systat/pigs.c create mode 100644 usr.bin/systat/swap.c create mode 100644 usr.bin/systat/systat.1 create mode 100644 usr.bin/systat/systat.h create mode 100644 usr.bin/systat/vmstat.c create mode 100644 usr.bin/tail/Makefile create mode 100644 usr.bin/tail/extern.h create mode 100644 usr.bin/tail/forward.c create mode 100644 usr.bin/tail/misc.c create mode 100644 usr.bin/tail/read.c create mode 100644 usr.bin/tail/reverse.c create mode 100644 usr.bin/tail/tail.1 create mode 100644 usr.bin/tail/tail.c create mode 100644 usr.bin/talk/Makefile create mode 100644 usr.bin/talk/ctl.c create mode 100644 usr.bin/talk/ctl_transact.c create mode 100644 usr.bin/talk/display.c create mode 100644 usr.bin/talk/get_addrs.c create mode 100644 usr.bin/talk/get_names.c create mode 100644 usr.bin/talk/init_disp.c create mode 100644 usr.bin/talk/invite.c create mode 100644 usr.bin/talk/io.c create mode 100644 usr.bin/talk/look_up.c create mode 100644 usr.bin/talk/msgs.c create mode 100644 usr.bin/talk/talk.1 create mode 100644 usr.bin/talk/talk.c create mode 100644 usr.bin/talk/talk.h create mode 100644 usr.bin/talk/talk_ctl.h create mode 100644 usr.bin/tcopy/Makefile create mode 100644 usr.bin/tcopy/pathnames.h create mode 100644 usr.bin/tcopy/tcopy.1 create mode 100644 usr.bin/tcopy/tcopy.c create mode 100644 usr.bin/tee/Makefile create mode 100644 usr.bin/tee/tee.1 create mode 100644 usr.bin/tee/tee.c create mode 100644 usr.bin/telnet/Makefile create mode 100644 usr.bin/telnet/README create mode 100644 usr.bin/telnet/authenc.c create mode 100644 usr.bin/telnet/commands.c create mode 100644 usr.bin/telnet/defines.h create mode 100644 usr.bin/telnet/externs.h create mode 100644 usr.bin/telnet/fdset.h create mode 100644 usr.bin/telnet/general.h create mode 100644 usr.bin/telnet/krb4-proto.h create mode 100644 usr.bin/telnet/main.c create mode 100644 usr.bin/telnet/network.c create mode 100644 usr.bin/telnet/ring.c create mode 100644 usr.bin/telnet/ring.h create mode 100644 usr.bin/telnet/sys_bsd.c create mode 100644 usr.bin/telnet/telnet.1 create mode 100644 usr.bin/telnet/telnet.c create mode 100644 usr.bin/telnet/terminal.c create mode 100644 usr.bin/telnet/tn3270.c create mode 100644 usr.bin/telnet/types.h create mode 100644 usr.bin/telnet/utilities.c create mode 100644 usr.bin/tftp/Makefile create mode 100644 usr.bin/tftp/extern.h create mode 100644 usr.bin/tftp/main.c create mode 100644 usr.bin/tftp/tftp.1 create mode 100644 usr.bin/tftp/tftp.c create mode 100644 usr.bin/tftp/tftpsubs.c create mode 100644 usr.bin/tftp/tftpsubs.h create mode 100644 usr.bin/time/Makefile create mode 100644 usr.bin/time/time.1 create mode 100644 usr.bin/time/time.c create mode 100644 usr.bin/tip/Makefile create mode 100644 usr.bin/tip/acu.c create mode 100644 usr.bin/tip/aculib/biz22.c create mode 100644 usr.bin/tip/aculib/biz31.c create mode 100644 usr.bin/tip/aculib/courier.c create mode 100644 usr.bin/tip/aculib/df.c create mode 100644 usr.bin/tip/aculib/dn11.c create mode 100644 usr.bin/tip/aculib/hayes.c create mode 100644 usr.bin/tip/aculib/t3000.c create mode 100644 usr.bin/tip/aculib/v3451.c create mode 100644 usr.bin/tip/aculib/v831.c create mode 100644 usr.bin/tip/aculib/ventel.c create mode 100644 usr.bin/tip/acutab.c create mode 100644 usr.bin/tip/cmds.c create mode 100644 usr.bin/tip/cmdtab.c create mode 100644 usr.bin/tip/cu.c create mode 100644 usr.bin/tip/hunt.c create mode 100644 usr.bin/tip/log.c create mode 100644 usr.bin/tip/partab.c create mode 100644 usr.bin/tip/pathnames.h create mode 100644 usr.bin/tip/remcap.c create mode 100644 usr.bin/tip/remote.c create mode 100644 usr.bin/tip/tip.1 create mode 100644 usr.bin/tip/tip.c create mode 100644 usr.bin/tip/tip.h create mode 100644 usr.bin/tip/tipout.c create mode 100644 usr.bin/tip/uucplock.c create mode 100644 usr.bin/tip/value.c create mode 100644 usr.bin/tip/vars.c create mode 100644 usr.bin/tn3270/Makefile create mode 100644 usr.bin/tn3270/Makefile.inc create mode 100644 usr.bin/tn3270/api/api_bsd.c create mode 100644 usr.bin/tn3270/api/api_exch.c create mode 100644 usr.bin/tn3270/api/api_exch.h create mode 100644 usr.bin/tn3270/api/apilib.c create mode 100644 usr.bin/tn3270/api/apilib.h create mode 100644 usr.bin/tn3270/api/asc_ebc.c create mode 100644 usr.bin/tn3270/api/asc_ebc.h create mode 100644 usr.bin/tn3270/api/astosc.c create mode 100644 usr.bin/tn3270/api/astosc.h create mode 100644 usr.bin/tn3270/api/dctype.c create mode 100644 usr.bin/tn3270/api/dctype.h create mode 100644 usr.bin/tn3270/api/disp_asc.c create mode 100644 usr.bin/tn3270/api/disp_asc.h create mode 100644 usr.bin/tn3270/api/ebc_disp.c create mode 100644 usr.bin/tn3270/api/ebc_disp.h create mode 100644 usr.bin/tn3270/ascii/default.map create mode 100644 usr.bin/tn3270/ascii/map3270.c create mode 100644 usr.bin/tn3270/ascii/map3270.h create mode 100644 usr.bin/tn3270/ascii/mset.c create mode 100644 usr.bin/tn3270/ascii/state.h create mode 100644 usr.bin/tn3270/ascii/termin.c create mode 100644 usr.bin/tn3270/ctlr/3180.kbd create mode 100644 usr.bin/tn3270/ctlr/3270pc.kbd create mode 100644 usr.bin/tn3270/ctlr/api.c create mode 100644 usr.bin/tn3270/ctlr/api.h create mode 100644 usr.bin/tn3270/ctlr/declare.h create mode 100644 usr.bin/tn3270/ctlr/externs.h create mode 100644 usr.bin/tn3270/ctlr/function.c create mode 100644 usr.bin/tn3270/ctlr/function.h create mode 100644 usr.bin/tn3270/ctlr/hostctlr.h create mode 100644 usr.bin/tn3270/ctlr/inbound.c create mode 100644 usr.bin/tn3270/ctlr/oia.c create mode 100644 usr.bin/tn3270/ctlr/oia.h create mode 100644 usr.bin/tn3270/ctlr/options.c create mode 100644 usr.bin/tn3270/ctlr/options.h create mode 100644 usr.bin/tn3270/ctlr/outbound.c create mode 100644 usr.bin/tn3270/ctlr/screen.h create mode 100644 usr.bin/tn3270/ctlr/scrnctlr.h create mode 100644 usr.bin/tn3270/ctlr/unix.kbd create mode 100644 usr.bin/tn3270/distribution/README create mode 100644 usr.bin/tn3270/distribution/arpa/makefile create mode 100644 usr.bin/tn3270/distribution/arpa/telnet.h create mode 100644 usr.bin/tn3270/distribution/makefile_4.2 create mode 100644 usr.bin/tn3270/distribution/sys_dos/makefile create mode 100644 usr.bin/tn3270/distribution/sys_dos/spint.h create mode 100644 usr.bin/tn3270/distribution/sys_dos/spintasm.asm create mode 100644 usr.bin/tn3270/distribution/sys_dos/spintc.c create mode 100644 usr.bin/tn3270/distribution/sys_dos/support.asm create mode 100644 usr.bin/tn3270/distribution/sys_dos/system.c create mode 100644 usr.bin/tn3270/distribution/sys_dos/termout.c create mode 100644 usr.bin/tn3270/distribution/sys_dos/termout.ext create mode 100644 usr.bin/tn3270/distribution/sys_dos/video.h create mode 100644 usr.bin/tn3270/distribution/telnet/Makefile_ultrix create mode 100644 usr.bin/tn3270/distribution/ultrix.curses create mode 100644 usr.bin/tn3270/distribution/utilities/adm3a.keys create mode 100644 usr.bin/tn3270/distribution/utilities/cross.c create mode 100644 usr.bin/tn3270/distribution/utilities/makefile create mode 100644 usr.bin/tn3270/distribution/utilities/srccmd/tar/makefile create mode 100644 usr.bin/tn3270/distribution/utilities/srccmd/tar/tar.h create mode 100644 usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c create mode 100644 usr.bin/tn3270/distribution/utilities/tncomp.h create mode 100644 usr.bin/tn3270/distribution/utilities/tnrecv.c create mode 100644 usr.bin/tn3270/general/genbsubs.c create mode 100644 usr.bin/tn3270/general/general.h create mode 100644 usr.bin/tn3270/general/globals.c create mode 100644 usr.bin/tn3270/general/globals.h create mode 100644 usr.bin/tn3270/general/vaxbsubs.s create mode 100644 usr.bin/tn3270/mset/Makefile create mode 100644 usr.bin/tn3270/mset/map3270.5 create mode 100644 usr.bin/tn3270/mset/mset.1 create mode 100644 usr.bin/tn3270/sys_curses/system.c create mode 100644 usr.bin/tn3270/sys_curses/telextrn.h create mode 100644 usr.bin/tn3270/sys_curses/terminal.h create mode 100644 usr.bin/tn3270/sys_curses/termout.c create mode 100644 usr.bin/tn3270/telnet/Makefile create mode 100644 usr.bin/tn3270/tn3270/Makefile create mode 100644 usr.bin/tn3270/tn3270/tn3270.1 create mode 100644 usr.bin/tn3270/tools/Makefile create mode 100644 usr.bin/tn3270/tools/mkastods/Makefile create mode 100644 usr.bin/tn3270/tools/mkastods/mkastods.c create mode 100644 usr.bin/tn3270/tools/mkastosc/Makefile create mode 100644 usr.bin/tn3270/tools/mkastosc/mkastosc.c create mode 100644 usr.bin/tn3270/tools/mkdctype/Makefile create mode 100644 usr.bin/tn3270/tools/mkdctype/ectype.c create mode 100644 usr.bin/tn3270/tools/mkdctype/ectype.h create mode 100644 usr.bin/tn3270/tools/mkdctype/mkdctype.c create mode 100644 usr.bin/tn3270/tools/mkdstoas/Makefile create mode 100644 usr.bin/tn3270/tools/mkdstoas/mkdstoas.c create mode 100644 usr.bin/tn3270/tools/mkhits/Makefile create mode 100644 usr.bin/tn3270/tools/mkhits/dohits.c create mode 100644 usr.bin/tn3270/tools/mkhits/dohits.h create mode 100644 usr.bin/tn3270/tools/mkhits/mkhits.c create mode 100644 usr.bin/tn3270/tools/mkmake.y create mode 100644 usr.bin/tn3270/tools/prt3270.c create mode 100644 usr.bin/touch/Makefile create mode 100644 usr.bin/touch/touch.1 create mode 100644 usr.bin/touch/touch.c create mode 100644 usr.bin/tput/Makefile create mode 100644 usr.bin/tput/clear.sh create mode 100644 usr.bin/tput/tput.1 create mode 100644 usr.bin/tput/tput.c create mode 100644 usr.bin/tr/Makefile create mode 100644 usr.bin/tr/extern.h create mode 100644 usr.bin/tr/str.c create mode 100644 usr.bin/tr/tr.1 create mode 100644 usr.bin/tr/tr.c create mode 100644 usr.bin/true/Makefile create mode 100644 usr.bin/true/true.1 create mode 100644 usr.bin/true/true.c create mode 100644 usr.bin/tset/Makefile create mode 100644 usr.bin/tset/extern.h create mode 100644 usr.bin/tset/map.c create mode 100644 usr.bin/tset/misc.c create mode 100644 usr.bin/tset/set.c create mode 100644 usr.bin/tset/term.c create mode 100644 usr.bin/tset/tset.1 create mode 100644 usr.bin/tset/tset.c create mode 100644 usr.bin/tset/wrterm.c create mode 100644 usr.bin/tsort/Makefile create mode 100644 usr.bin/tsort/tsort.1 create mode 100644 usr.bin/tsort/tsort.c create mode 100644 usr.bin/tty/Makefile create mode 100644 usr.bin/tty/tty.1 create mode 100644 usr.bin/tty/tty.c create mode 100644 usr.bin/ul/Makefile create mode 100644 usr.bin/ul/ul.1 create mode 100644 usr.bin/ul/ul.c create mode 100644 usr.bin/uname/Makefile create mode 100644 usr.bin/uname/uname.1 create mode 100644 usr.bin/uname/uname.c create mode 100644 usr.bin/unexpand/Makefile create mode 100644 usr.bin/unexpand/unexpand.c create mode 100644 usr.bin/unifdef/Makefile create mode 100644 usr.bin/unifdef/unifdef.1 create mode 100644 usr.bin/unifdef/unifdef.c create mode 100644 usr.bin/uniq/Makefile create mode 100644 usr.bin/uniq/uniq.1 create mode 100644 usr.bin/uniq/uniq.c create mode 100644 usr.bin/unvis/Makefile create mode 100644 usr.bin/unvis/unvis.1 create mode 100644 usr.bin/unvis/unvis.c create mode 100644 usr.bin/users/Makefile create mode 100644 usr.bin/users/users.1 create mode 100644 usr.bin/users/users.c create mode 100644 usr.bin/uucp/acucntrl/Makefile create mode 100644 usr.bin/uucp/acucntrl/acucntrl.8 create mode 100644 usr.bin/uucp/acucntrl/acucntrl.c create mode 100644 usr.bin/uucp/uupoll/Makefile create mode 100644 usr.bin/uucp/uupoll/uupoll.8 create mode 100644 usr.bin/uucp/uupoll/uupoll.c create mode 100644 usr.bin/uucp/uuq/Makefile create mode 100644 usr.bin/uucp/uuq/uuq.1 create mode 100644 usr.bin/uucp/uuq/uuq.c create mode 100644 usr.bin/uucp/uusend/Makefile create mode 100644 usr.bin/uucp/uusend/uusend.1 create mode 100644 usr.bin/uucp/uusend/uusend.c create mode 100644 usr.bin/uucp/uusnap/Makefile create mode 100644 usr.bin/uucp/uusnap/uusnap.8 create mode 100644 usr.bin/uucp/uusnap/uusnap.c create mode 100644 usr.bin/uudecode/Makefile create mode 100644 usr.bin/uudecode/uudecode.c create mode 100644 usr.bin/uuencode/Makefile create mode 100644 usr.bin/uuencode/uuencode.1 create mode 100644 usr.bin/uuencode/uuencode.c create mode 100644 usr.bin/uuencode/uuencode.format.5 create mode 100644 usr.bin/vacation/Makefile create mode 100644 usr.bin/vacation/vacation.1 create mode 100644 usr.bin/vacation/vacation.c create mode 100644 usr.bin/vgrind/Makefile create mode 100644 usr.bin/vgrind/RETEST/Makefile create mode 100644 usr.bin/vgrind/RETEST/retest.c create mode 100644 usr.bin/vgrind/extern.h create mode 100644 usr.bin/vgrind/pathnames.h create mode 100644 usr.bin/vgrind/regexp.c create mode 100644 usr.bin/vgrind/tmac.vgrind create mode 100644 usr.bin/vgrind/vfontedpr.c create mode 100644 usr.bin/vgrind/vgrind.1 create mode 100644 usr.bin/vgrind/vgrind.sh create mode 100644 usr.bin/vgrind/vgrindefs.5 create mode 100644 usr.bin/vgrind/vgrindefs.c create mode 100644 usr.bin/vgrind/vgrindefs.src create mode 100644 usr.bin/vis/Makefile create mode 100644 usr.bin/vis/foldit.c create mode 100644 usr.bin/vis/vis.1 create mode 100644 usr.bin/vis/vis.c create mode 100644 usr.bin/vmstat/Makefile create mode 100644 usr.bin/vmstat/names.c create mode 100644 usr.bin/vmstat/vmstat.8 create mode 100644 usr.bin/vmstat/vmstat.c create mode 100644 usr.bin/w/Makefile create mode 100644 usr.bin/w/extern.h create mode 100644 usr.bin/w/pr_time.c create mode 100644 usr.bin/w/proc_compare.c create mode 100644 usr.bin/w/uptime.1 create mode 100644 usr.bin/w/w.1 create mode 100644 usr.bin/w/w.c create mode 100644 usr.bin/wall/Makefile create mode 100644 usr.bin/wall/ttymsg.c create mode 100644 usr.bin/wall/wall.1 create mode 100644 usr.bin/wall/wall.c create mode 100644 usr.bin/wc/Makefile create mode 100644 usr.bin/wc/wc.1 create mode 100644 usr.bin/wc/wc.c create mode 100644 usr.bin/what/Makefile create mode 100644 usr.bin/what/what.1 create mode 100644 usr.bin/what/what.c create mode 100644 usr.bin/whatis/Makefile create mode 100644 usr.bin/whatis/whatis.1 create mode 100644 usr.bin/whatis/whatis.c create mode 100644 usr.bin/whereis/Makefile create mode 100644 usr.bin/who/Makefile create mode 100644 usr.bin/who/who.1 create mode 100644 usr.bin/who/who.c create mode 100644 usr.bin/whois/Makefile create mode 100644 usr.bin/whois/whois.1 create mode 100644 usr.bin/whois/whois.c create mode 100644 usr.bin/window/:tt create mode 100644 usr.bin/window/:tty create mode 100644 usr.bin/window/:var create mode 100644 usr.bin/window/:ww create mode 100644 usr.bin/window/Makefile create mode 100644 usr.bin/window/README create mode 100644 usr.bin/window/alias.h create mode 100644 usr.bin/window/char.c create mode 100644 usr.bin/window/char.h create mode 100644 usr.bin/window/cmd.c create mode 100644 usr.bin/window/cmd1.c create mode 100644 usr.bin/window/cmd2.c create mode 100644 usr.bin/window/cmd3.c create mode 100644 usr.bin/window/cmd4.c create mode 100644 usr.bin/window/cmd5.c create mode 100644 usr.bin/window/cmd6.c create mode 100644 usr.bin/window/cmd7.c create mode 100644 usr.bin/window/compress.c create mode 100644 usr.bin/window/context.c create mode 100644 usr.bin/window/context.h create mode 100644 usr.bin/window/defs.h create mode 100644 usr.bin/window/error.c create mode 100644 usr.bin/window/lcmd.c create mode 100644 usr.bin/window/lcmd.h create mode 100644 usr.bin/window/lcmd1.c create mode 100644 usr.bin/window/lcmd2.c create mode 100644 usr.bin/window/local.h create mode 100644 usr.bin/window/main.c create mode 100644 usr.bin/window/mloop.c create mode 100644 usr.bin/window/parser.h create mode 100644 usr.bin/window/parser1.c create mode 100644 usr.bin/window/parser2.c create mode 100644 usr.bin/window/parser3.c create mode 100644 usr.bin/window/parser4.c create mode 100644 usr.bin/window/parser5.c create mode 100644 usr.bin/window/scanner.c create mode 100644 usr.bin/window/startup.c create mode 100644 usr.bin/window/string.c create mode 100644 usr.bin/window/string.h create mode 100644 usr.bin/window/token.h create mode 100644 usr.bin/window/tt.h create mode 100644 usr.bin/window/ttf100.c create mode 100644 usr.bin/window/ttgeneric.c create mode 100644 usr.bin/window/tth19.c create mode 100644 usr.bin/window/tth29.c create mode 100644 usr.bin/window/ttinit.c create mode 100644 usr.bin/window/ttoutput.c create mode 100644 usr.bin/window/tttermcap.c create mode 100644 usr.bin/window/tttvi925.c create mode 100644 usr.bin/window/ttwyse60.c create mode 100644 usr.bin/window/ttwyse75.c create mode 100644 usr.bin/window/ttzapple.c create mode 100644 usr.bin/window/ttzentec.c create mode 100644 usr.bin/window/value.h create mode 100644 usr.bin/window/var.c create mode 100644 usr.bin/window/var.h create mode 100644 usr.bin/window/win.c create mode 100644 usr.bin/window/window.1 create mode 100644 usr.bin/window/windowrc create mode 100644 usr.bin/window/ww.h create mode 100644 usr.bin/window/wwadd.c create mode 100644 usr.bin/window/wwalloc.c create mode 100644 usr.bin/window/wwbox.c create mode 100644 usr.bin/window/wwchild.c create mode 100644 usr.bin/window/wwclose.c create mode 100644 usr.bin/window/wwclreol.c create mode 100644 usr.bin/window/wwclreos.c create mode 100644 usr.bin/window/wwcursor.c create mode 100644 usr.bin/window/wwdata.c create mode 100644 usr.bin/window/wwdelchar.c create mode 100644 usr.bin/window/wwdelete.c create mode 100644 usr.bin/window/wwdelline.c create mode 100644 usr.bin/window/wwdump.c create mode 100644 usr.bin/window/wwend.c create mode 100644 usr.bin/window/wwenviron.c create mode 100644 usr.bin/window/wwerror.c create mode 100644 usr.bin/window/wwflush.c create mode 100644 usr.bin/window/wwframe.c create mode 100644 usr.bin/window/wwgets.c create mode 100644 usr.bin/window/wwinit.c create mode 100644 usr.bin/window/wwinschar.c create mode 100644 usr.bin/window/wwinsline.c create mode 100644 usr.bin/window/wwiomux.c create mode 100644 usr.bin/window/wwlabel.c create mode 100644 usr.bin/window/wwmisc.c create mode 100644 usr.bin/window/wwmove.c create mode 100644 usr.bin/window/wwopen.c create mode 100644 usr.bin/window/wwprintf.c create mode 100644 usr.bin/window/wwpty.c create mode 100644 usr.bin/window/wwputc.c create mode 100644 usr.bin/window/wwputs.c create mode 100644 usr.bin/window/wwredraw.c create mode 100644 usr.bin/window/wwredrawwin.c create mode 100644 usr.bin/window/wwrint.c create mode 100644 usr.bin/window/wwscroll.c create mode 100644 usr.bin/window/wwsize.c create mode 100644 usr.bin/window/wwspawn.c create mode 100644 usr.bin/window/wwsuspend.c create mode 100644 usr.bin/window/wwterminfo.c create mode 100644 usr.bin/window/wwtty.c create mode 100644 usr.bin/window/wwunframe.c create mode 100644 usr.bin/window/wwupdate.c create mode 100644 usr.bin/window/wwwrite.c create mode 100644 usr.bin/window/xx.c create mode 100644 usr.bin/window/xx.h create mode 100644 usr.bin/window/xxflush.c create mode 100644 usr.bin/write/Makefile create mode 100644 usr.bin/write/write.1 create mode 100644 usr.bin/write/write.c create mode 100644 usr.bin/xargs/Makefile create mode 100644 usr.bin/xargs/pathnames.h create mode 100644 usr.bin/xargs/xargs.1 create mode 100644 usr.bin/xargs/xargs.c create mode 100644 usr.bin/xinstall/Makefile create mode 100644 usr.bin/xinstall/install.1 create mode 100644 usr.bin/xinstall/pathnames.h create mode 100644 usr.bin/xinstall/xinstall.c create mode 100644 usr.bin/xstr/Makefile create mode 100644 usr.bin/xstr/pathnames.h create mode 100644 usr.bin/xstr/xstr.1 create mode 100644 usr.bin/xstr/xstr.c create mode 100644 usr.bin/yacc/ACKNOWLEDGEMENTS create mode 100644 usr.bin/yacc/Makefile create mode 100644 usr.bin/yacc/NEW_FEATURES create mode 100644 usr.bin/yacc/NOTES create mode 100644 usr.bin/yacc/README create mode 100644 usr.bin/yacc/closure.c create mode 100644 usr.bin/yacc/defs.h create mode 100644 usr.bin/yacc/error.c create mode 100644 usr.bin/yacc/lalr.c create mode 100644 usr.bin/yacc/lr0.c create mode 100644 usr.bin/yacc/main.c create mode 100644 usr.bin/yacc/mkpar.c create mode 100644 usr.bin/yacc/output.c create mode 100644 usr.bin/yacc/reader.c create mode 100644 usr.bin/yacc/skeleton.c create mode 100644 usr.bin/yacc/symtab.c create mode 100644 usr.bin/yacc/test/error.output create mode 100644 usr.bin/yacc/test/error.tab.c create mode 100644 usr.bin/yacc/test/error.tab.h create mode 100644 usr.bin/yacc/test/error.y create mode 100644 usr.bin/yacc/test/ftp.output create mode 100644 usr.bin/yacc/test/ftp.tab.c create mode 100644 usr.bin/yacc/test/ftp.tab.h create mode 100644 usr.bin/yacc/test/ftp.y create mode 100644 usr.bin/yacc/verbose.c create mode 100644 usr.bin/yacc/warshall.c create mode 100644 usr.bin/yacc/yacc.1 create mode 100644 usr.bin/yacc/yyfix.1 create mode 100644 usr.bin/yacc/yyfix.sh create mode 100644 usr.bin/yes/Makefile create mode 100644 usr.bin/yes/yes.1 create mode 100644 usr.bin/yes/yes.c diff --git a/usr.bin/Makefile b/usr.bin/Makefile new file mode 100644 index 0000000..f6028ca --- /dev/null +++ b/usr.bin/Makefile @@ -0,0 +1,38 @@ +# @(#)Makefile 8.3 (Berkeley) 1/7/94 + +SUBDIR= apply apropos ar at banner basename bc bdes biff cal calendar \ + cap_mkdb checknr chflags chpass cksum col colcrt colrm column \ + comm compress cpp ctags cut dc deroff diction diff dirname du \ + env error ex expand false file find finger fmt fold fpr from \ + fsplit fstat ftp gcore gprof graph grep head hexdump id indent \ + join jot kdump ktrace lam last lastcomm learn leave locate \ + lock logger login logname lorder m4 mail make man mesg mkdep \ + mkfifo mklocale mkstr more msgs mt netstat nfsstat nice nm nohup \ + pagesize passwd paste patch plot pr printenv printf ptx quota \ + ranlib rdist renice rev rlogin rs rsh ruptime rwho sccs \ + script sed shar showmount size soelim sort spell spline split \ + strings strip struct su talk tcopy tee telnet tftp time tip \ + tn3270 touch tput tr true tset tsort tty ul uname unexpand \ + unifdef uniq units unvis users uucp uudecode uuencode vacation \ + vgrind vis w wall wc what whatis whereis who whois window write \ + xargs xinstall xsend xstr yacc yes + +# Cmp, look and tail all use mmap, so new-VM only. +# F77 and pascal are VAX/Tahoe only. +.if ${MACHINE} == "hp300" +SUBDIR+=cmp ld look systat tail vmstat +.elif ${MACHINE} == "i386" +SUBDIR+=cmp ld look systat tail vmstat +.elif ${MACHINE} == "luna68k" +SUBDIR+=cmp ld look systat tail vmstat +.elif ${MACHINE} == "mips" +SUBDIR+=cmp look systat tail vmstat +.elif ${MACHINE} == "sparc" +SUBDIR+=cmp ld look tail vmstat.sparc +.elif ${MACHINE} == "tahoe" +SUBDIR+=f77 pascal systat vmstat +.elif ${MACHINE} == "vax" +SUBDIR+=f77 pascal systat vmstat +.endif + +.include diff --git a/usr.bin/Makefile.inc b/usr.bin/Makefile.inc new file mode 100644 index 0000000..84bfd7f --- /dev/null +++ b/usr.bin/Makefile.inc @@ -0,0 +1,3 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/6/93 + +BINDIR?= /usr/bin diff --git a/usr.bin/apply/Makefile b/usr.bin/apply/Makefile new file mode 100644 index 0000000..59f358e --- /dev/null +++ b/usr.bin/apply/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= apply + +.include diff --git a/usr.bin/apply/apply.1 b/usr.bin/apply/apply.1 new file mode 100644 index 0000000..dd7a9ee --- /dev/null +++ b/usr.bin/apply/apply.1 @@ -0,0 +1,129 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)apply.1 8.2 (Berkeley) 4/4/94 +.\" +.Dd April 4, 1994 +.Dt APPLY 1 +.Os BSD 4.2 +.Sh NAME +.Nm apply +.Nd apply a command to a set of arguments +.Sh SYNOPSIS +.Nm apply +.Op Fl a Ns Ar c +.Op Fl Ns Ar # +.Ar command argument ... +.Sh DESCRIPTION +.Nm Apply +runs the named +.Ar command +on each +argument +.Ar argument +in turn. +.Pp +Character sequences of the form +.Dq Li \&%d +in +.Ar command , +where +.Dq Li d +is a digit from 1 to 9, are replaced by the +.Li d Ns \'th +following unused +.Ar argument . +In this case, the largest digit number of arguments are discarded for +each execution of +.Ar command . +.Pp +The options are as follows: +.Bl -tag -width "-ac" +.It Fl Ns Ar # +Normally arguments are taken singly; the optional number +.Fl # +specifies the number of arguments to be passed to +.Ar command . +If the number is zero, +.Ar command +is run, without arguments, once for each +.Ar argument . +.Pp +If any sequences of +.Dq Li \&%d +occur in command, the +.Fl n +option is ignored. +.It Fl a Ns Ar c +The use of the character +.Dq Li % +as a magic character may be changed with the +.Fl a +option. +.El +.Sh ENVIRONMENT VARIABLES +The following environment variable affects the execution of +.Nm apply : +.Bl -tag -width SHELL +.It Ev SHELL +Pathname of shell to use. +If this variable is not defined, the Bourne shell is used. +.El +.Sh EXAMPLES +.Bl -tag -width apply -compact +.It Li "apply echo a*" +is similar to ls(1); +.It Li "apply \-2 cmp a1 b1 a2 b2 a3 b3" +compares the `a' files to the `b' files; +.It Li "apply \-0 who 1 2 3 4 5" +runs who(1) 5 times; and +.It Li "apply \'ln %1 /usr/joe\'" * +links all files in the current directory to the directory +.Pa /usr/joe . +.El +.Sh Files +.Bl -tag -width /bin/sh -compact +.It Pa /bin/sh +Default shell +.El +.Sh AUTHOR +Rob Pike +.Sh BUGS +Shell metacharacters in +.Ar command +may have bizarre effects; it is best to enclose complicated +commands in single quotes +.Pq Sq . +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr.bin/apply/apply.c b/usr.bin/apply/apply.c new file mode 100644 index 0000000..a8634a9 --- /dev/null +++ b/usr.bin/apply/apply.c @@ -0,0 +1,234 @@ +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +void usage __P((void)); +int system __P((const char *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, clen, debug, i, l, magic, n, nargs, rval; + char *c, *cmd, *p, *q; + + debug = 0; + magic = '%'; /* Default magic char is `%'. */ + nargs = -1; + while ((ch = getopt(argc, argv, "a:d0123456789")) != EOF) + switch (ch) { + case 'a': + if (optarg[1] != '\0') + errx(1, + "illegal magic character specification."); + magic = optarg[0]; + break; + case 'd': + debug = 1; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (nargs != -1) + errx(1, + "only one -# argument may be specified."); + nargs = optopt - '0'; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + /* + * The command to run is argv[0], and the args are argv[1..]. + * Look for %digit references in the command, remembering the + * largest one. + */ + for (n = 0, p = argv[0]; *p != '\0'; ++p) + if (p[0] == magic && isdigit(p[1]) && p[1] != '0') { + ++p; + if (p[0] - '0' > n) + n = p[0] - '0'; + } + + /* + * If there were any %digit references, then use those, otherwise + * build a new command string with sufficient %digit references at + * the end to consume (nargs) arguments each time round the loop. + * Allocate enough space to hold the maximum command. + */ + if ((cmd = malloc(sizeof("exec ") - 1 + + strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1)) == NULL) + err(1, NULL); + + if (n == 0) { + /* If nargs not set, default to a single argument. */ + if (nargs == -1) + nargs = 1; + + p = cmd; + p += sprintf(cmd, "exec %s", argv[0]); + for (i = 1; i <= nargs; i++) + p += sprintf(p, " %c%d", magic, i); + + /* + * If nargs set to the special value 0, eat a single + * argument for each command execution. + */ + if (nargs == 0) + nargs = 1; + } else { + (void)sprintf(cmd, "exec %s", argv[0]); + nargs = n; + } + + /* + * Grab some space in which to build the command. Allocate + * as necessary later, but no reason to build it up slowly + * for the normal case. + */ + if ((c = malloc(clen = 1024)) == NULL) + err(1, NULL); + + /* + * (argc) and (argv) are still offset by one to make it simpler to + * expand %digit references. At the end of the loop check for (argc) + * equals 1 means that all the (argv) has been consumed. + */ + for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) { + /* + * Find a max value for the command length, and ensure + * there's enough space to build it. + */ + for (l = strlen(cmd), i = 0; i < nargs; i++) + l += strlen(argv[i]); + if (l > clen && (c = realloc(c, clen = l)) == NULL) + err(1, NULL); + + /* Expand command argv references. */ + for (p = cmd, q = c; *p != '\0'; ++p) + if (p[0] == magic && isdigit(p[1]) && p[1] != '0') + q += sprintf(q, "%s", argv[(++p)[0] - '0']); + else + *q++ = *p; + + /* Terminate the command string. */ + *q = '\0'; + + /* Run the command. */ + if (debug) + (void)printf("%s\n", c); + else + if (system(c)) + rval = 1; + } + + if (argc != 1) + errx(1, "expecting additional argument%s after \"%s\"", + (nargs - argc) ? "s" : "", argv[argc - 1]); + exit(rval); +} + +/* + * system -- + * Private version of system(3). Use the user's SHELL environment + * variable as the shell to execute. + */ +int +system(command) + const char *command; +{ + static char *name, *shell; + union wait pstat; + pid_t pid; + int omask; + sig_t intsave, quitsave; + + if (shell == NULL) { + if ((shell = getenv("SHELL")) == NULL) + shell = _PATH_BSHELL; + if ((name = strrchr(shell, '/')) == NULL) + name = shell; + else + ++name; + } + if (!command) /* just checking... */ + return(1); + + omask = sigblock(sigmask(SIGCHLD)); + switch(pid = vfork()) { + case -1: /* error */ + err(1, "fork"); + case 0: /* child */ + (void)sigsetmask(omask); + execl(shell, name, "-c", command, NULL); + err(1, "%s", shell); + } + intsave = signal(SIGINT, SIG_IGN); + quitsave = signal(SIGQUIT, SIG_IGN); + pid = waitpid(pid, (int *)&pstat, 0); + (void)sigsetmask(omask); + (void)signal(SIGINT, intsave); + (void)signal(SIGQUIT, quitsave); + return(pid == -1 ? -1 : pstat.w_status); +} + +void +usage() +{ + + (void)fprintf(stderr, + "usage: apply [-a magic] [-0123456789] command arguments ...\n"); + exit(1); +} diff --git a/usr.bin/apropos/Makefile b/usr.bin/apropos/Makefile new file mode 100644 index 0000000..028a42c --- /dev/null +++ b/usr.bin/apropos/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= apropos +SRCS= apropos.c config.c +.PATH: ${.CURDIR}/../man + +.include diff --git a/usr.bin/apropos/apropos.1 b/usr.bin/apropos/apropos.1 new file mode 100644 index 0000000..eb68f37 --- /dev/null +++ b/usr.bin/apropos/apropos.1 @@ -0,0 +1,120 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)apropos.1 8.1 (Berkeley) 6/29/93 +.\" +.Dd June 29, 1993 +.Dt APROPOS 1 +.Os +.Sh NAME +.Nm apropos +.Nd locate commands by keyword lookup +.Sh SYNOPSIS +.Nm apropos +.Op Fl M Ar path +.Op Fl m Ar path +.Ar keyword ... +.Sh DESCRIPTION +.Nm Apropos +shows which manual pages contain instances of any of the given +.Ar keyword(s) +in their title line. +Each word is considered separately and case of letters is ignored. +Words which are part of other words are considered; when looking for +.Dq compile , +.Nm apropos +will also list all instances of +.Dq compiler . +.Pp +If the line output by +.Nm apropos +starts +.Dq Li name(section) ... +you can enter +.Dq Li man section name +to get +its documentation. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl M +Override the list of standard directories +.Nm apropos +searches for a database named +.Pa whatis.db . +The supplied +.Ar path +must be a colon +.Dq \&: +separated list of directories. +This search path may also be set using the environment variable +.Ev MANPATH . +.It Fl m +Augment the list of standard directories +.Nm apropos +searches for its database. +The supplied +.Ar path +must be a colon +.Dq \&: +separated list of directories. +These directories will be searched before the standard directories, +or the directories supplied with the +.Fl M +option or the +.Ev MANPATH +environment variable. +.Sh ENVIRONMENT +.Bl -tag -width MANPATH +.It Ev MANPATH +The standard search path used by +.Xr man 1 +may be overridden by specifying a path in the +.Ev MANPATH +environment variable. +The format of the path is a colon +.Dq \&: +separated list of directories. +.El +.Sh FILES +.Bl -tag -width whatis.db -compact +.It Pa whatis.db +name of the apropos database +.El +.Sh SEE ALSO +.Xr man 1 , +.Xr whatis 1 , +.Xr whereis 1 +.Sh HISTORY +The +.Nm apropos +command appeared in +.Bx 3.0 . diff --git a/usr.bin/apropos/apropos.c b/usr.bin/apropos/apropos.c new file mode 100644 index 0000000..a0e0525 --- /dev/null +++ b/usr.bin/apropos/apropos.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)apropos.c 8.7 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../man/config.h" +#include "../man/pathnames.h" + +static int *found, foundman; + +void apropos __P((char **, char *, int)); +void lowstr __P((char *, char *)); +int match __P((char *, char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + ENTRY *ep; + TAG *tp; + int ch, rv; + char *conffile, **p, *p_augment, *p_path; + + conffile = NULL; + p_augment = p_path = NULL; + while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF) + switch (ch) { + case 'C': + conffile = optarg; + break; + case 'M': + case 'P': /* backward compatible */ + p_path = optarg; + break; + case 'm': + p_augment = optarg; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + if (argc < 1) + usage(); + + if ((found = malloc((u_int)argc * sizeof(int))) == NULL) + err(1, NULL); + memset(found, 0, argc * sizeof(int)); + + for (p = argv; *p; ++p) /* convert to lower-case */ + lowstr(*p, *p); + + if (p_augment) + apropos(argv, p_augment, 1); + if (p_path || (p_path = getenv("MANPATH"))) + apropos(argv, p_path, 1); + else { + config(conffile); + ep = (tp = getlist("_whatdb")) == NULL ? + NULL : tp->list.tqh_first; + for (; ep != NULL; ep = ep->q.tqe_next) + apropos(argv, ep->s, 0); + } + + if (!foundman) + errx(1, "no %s file found", _PATH_WHATIS); + + rv = 1; + for (p = argv; *p; ++p) + if (found[p - argv]) + rv = 0; + else + (void)printf("%s: nothing appropriate\n", *p); + exit(rv); +} + +void +apropos(argv, path, buildpath) + char **argv, *path; + int buildpath; +{ + char *end, *name, **p; + char buf[LINE_MAX + 1], wbuf[LINE_MAX + 1]; + + for (name = path; name; name = end) { /* through name list */ + if (end = strchr(name, ':')) + *end++ = '\0'; + + if (buildpath) { + char hold[MAXPATHLEN + 1]; + + (void)sprintf(hold, "%s/%s", name, _PATH_WHATIS); + name = hold; + } + + if (!freopen(name, "r", stdin)) + continue; + + foundman = 1; + + /* for each file found */ + while (fgets(buf, sizeof(buf), stdin)) { + if (!strchr(buf, '\n')) { + warnx("%s: line too long", name); + continue; + } + lowstr(buf, wbuf); + for (p = argv; *p; ++p) + if (match(wbuf, *p)) { + (void)printf("%s", buf); + found[p - argv] = 1; + + /* only print line once */ + while (*++p) + if (match(wbuf, *p)) + found[p - argv] = 1; + break; + } + } + } +} + +/* + * match -- + * match anywhere the string appears + */ +int +match(bp, str) + char *bp, *str; +{ + int len; + char test; + + if (!*bp) + return (0); + /* backward compatible: everything matches empty string */ + if (!*str) + return (1); + for (test = *str++, len = strlen(str); *bp;) + if (test == *bp++ && !strncmp(bp, str, len)) + return (1); + return (0); +} + +/* + * lowstr -- + * convert a string to lower case + */ +void +lowstr(from, to) + char *from, *to; +{ + char ch; + + while ((ch = *from++) && ch != '\n') + *to++ = isupper(ch) ? tolower(ch) : ch; + *to = '\0'; +} + +/* + * usage -- + * print usage message and die + */ +void +usage() +{ + + (void)fprintf(stderr, + "usage: apropos [-C file] [-M path] [-m path] keyword ...\n"); + exit(1); +} diff --git a/usr.bin/ar/Makefile b/usr.bin/ar/Makefile new file mode 100644 index 0000000..f79edaa --- /dev/null +++ b/usr.bin/ar/Makefile @@ -0,0 +1,16 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ar +CFLAGS+=-I${.CURDIR} +SRCS= append.c ar.c archive.c contents.c delete.c extract.c misc.c \ + move.c print.c replace.c +MAN1= ar.0 +CLEANFILES=ar.5.0 + +ar.0: ar.5.0 + +afterinstall: + install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} ar.5.0 \ + ${DESTDIR}${MANDIR}5/ar.0 + +.include diff --git a/usr.bin/ar/append.c b/usr.bin/ar/append.c new file mode 100644 index 0000000..89db986 --- /dev/null +++ b/usr.bin/ar/append.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)append.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +/* + * append -- + * Append files to the archive - modifies original archive or creates + * a new archive if named archive does not exist. + */ +int +append(argv) + char **argv; +{ + int afd, fd, eval; + char *file; + CF cf; + struct stat sb; + + afd = open_archive(O_CREAT|O_RDWR); + if (lseek(afd, (off_t)0, SEEK_END) == (off_t)-1) + error(archive); + + /* Read from disk, write to an archive; pad on write. */ + SETCF(0, 0, afd, archive, WPAD); + for (eval = 0; file = *argv++;) { + if ((fd = open(file, O_RDONLY)) < 0) { + warn("%s", file); + eval = 1; + continue; + } + if (options & AR_V) + (void)printf("q - %s\n", file); + cf.rfd = fd; + cf.rname = file; + put_arobj(&cf, &sb); + (void)close(fd); + } + close_archive(afd); + return (eval); +} diff --git a/usr.bin/ar/ar.1 b/usr.bin/ar/ar.1 new file mode 100644 index 0000000..026aed6 --- /dev/null +++ b/usr.bin/ar/ar.1 @@ -0,0 +1,257 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Hugh Smith at The University of Guelph. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ar.1 8.1 (Berkeley) 6/29/93 +.\" +.TH AR 1 "June 29, 1993" +.AT 3 +.SH NAME +ar \- create and maintain library archives +.SH SYNOPSIS +.nf +.ft B +ar -d [-Tv] archive file ... +ar -m [-Tv] archive file ... +ar -m [-abiTv] position archive file ... +ar -p [-Tv] archive [file ...] +ar -q [-cTv] archive file ... +ar -r [-cuTv] archive file ... +ar -r [-abciuTv] position archive file ... +ar -t [-Tv] archive [file ...] +ar -x [-ouTv] archive [file ...] +.fi +.ft R +.SH DESCRIPTION +The +.I ar +utility creates and maintains groups of files combined into an archive. +Once an archive has been created, new files can be added and existing +files can be extracted, deleted, or replaced. +.PP +Files are named in the archive by a single component, i.e., if a file +referenced by a path containing a slash (``/'') is archived it will be +named by the last component of that path. +When matching paths listed on the command line against file names stored +in the archive, only the last component of the path will be compared. +.PP +All informational and error messages use the path listed on the command +line, if any was specified; otherwise the name in the archive is used. +If multiple files in the archive have the same name, and paths are listed +on the command line to ``select'' archive files for an operation, only the +.B first +file with a matching name will be selected. +.PP +The normal use of +.I ar +is for the creation and maintenance of libraries suitable for use with +the loader (see +.IR ld (1)), +although it is not restricted to this purpose. +The options are as follows: +.TP +\-a +A positioning modifier used with the options \-r and \-m. +The files are entered or moved +.B after +the archive member +.IR position , +which must be specified. +.TP +\-b +A positioning modifier used with the options \-r and \-m. +The files are entered or moved +.B before +the archive member +.IR position , +which must be specified. +.TP +\-c +Whenever an archive is created, an informational message to that effect +is written to standard error. +If the \-c option is specified, +.I ar +creates the archive silently. +.TP +\-d +Delete the specified archive files. +.TP +\-i +Identical to the \-b option. +.TP +\-m +Move the specified archive files within the archive. +If one of the options \-a, \-b or \-i is specified, the files are moved +before or after the +.I position +file in the archive. +If none of those options are specified, the files are moved +to the end of the archive. +.TP +\-o +Set the access and modification times of extracted files to the +modification time of the file when it was entered into the archive. +This will fail if the user is not the owner of the extracted file +or the super-user. +.TP +\-p +Write the contents of the specified archive files to the standard output. +If no files are specified, the contents of all the files in the archive +are written in the order they appear in the archive. +.TP +\-q +(Quickly) append the specified files to the archive. +If the archive does not exist a new archive file is created. +Much faster than the \-r option, when creating a large archive +piece-by-piece, as no checking is done to see if the files already +exist in the archive. +.TP +\-r +Replace or add the specified files to the archive. +If the archive does not exist a new archive file is created. +Files that replace existing files do not change the order of the files +within the archive. +New files are appended to the archive unless one of the options \-a, \-b +or \-i is specified. +.TP +\-T +Select and/or name archive members using only the first fifteen characters +of the archive member or command line file name. +The historic archive format had sixteen bytes for the name, but some +historic archiver and loader implementations were unable to handle names +that used the entire space. +This means that file names that are not unique in their first fifteen +characters can subsequently be confused. +A warning message is printed to the standard error output if any file +names are truncated. +(See +.IR ar (5) +for more information.) +.TP +\-t +List the specified files in the order in which they appear in the archive, +each on a separate line. +If no files are specified, all files in the archive are listed. +.TP +\-u +Update files. +When used with the \-r option, files in the archive will be replaced +only if the disk file has a newer modification time than the file in +the archive. +When used with the \-x option, files in the archive will be extracted +only if the archive file has a newer modification time than the file +on disk. +.TP +\-v +Provide verbose output. +When used with the \-d, \-m, \-q or \-x options, +.I ar +gives a file-by-file description of the archive modification. +This description consists of three, white-space separated fields: the +option letter, a dash (``-'') and the file name. +When used with the \-r option, +.I ar +displays the description as above, but the initial letter is an ``a'' if +the file is added to the archive and an ``r'' if the file replaces a file +already in the archive. +.IP +When used with the \-p option, +the name of each printed file, +enclosed in less-than (``<'') and greater-than (``>'') characters, +is written to the standard output before +the contents of the file; +it is preceded by a single newline character, and +followed by two newline characters. +.IP +When used with the \-t option, +.I ar +displays an ``ls -l'' style listing of information about the members of +the archive. +This listing consists of eight, white-space separated fields: +the file permissions (see +.IR strmode (3)), +the decimal user and group ID's separated by a single slash (``/''), +the file size (in bytes), the file modification time (in the +.IR date (1) +format ``%b %e %H:%M %Y''), and the name of the file. +.TP +\-x +Extract the specified archive members into the files named by the command +line arguments. +If no members are specified, all the members of the archive are extracted into +the current directory. +.IP +If the file does not exist, it is created; if it does exist, the owner +and group will be unchanged. +The file access and modification times are the time of the extraction +(but see the \-o option). +The file permissions will be set to those of the file when it was entered +into the archive; this will fail if the user is not the owner of the +extracted file or the super-user. +.PP +The +.I ar +utility exits 0 on success, and >0 if an error occurs. +.SH ENVIRONMENT +.TP +TMPDIR +The pathname of the directory to use when creating temporary files. +.SH FILES +.TP 14 +/tmp +default temporary file directory +.TP 14 +ar.XXXXXX +temporary file names +.SH COMPATIBILITY +By default, +.I ar +writes archives that may be incompatible with historic archives, as +the format used for storing archive members with names longer than +fifteen characters has changed. +This implementation of +.I ar +is backward compatible with previous versions of +.I ar +in that it can read and write (using the \-T option) historic archives. +The \-T option is provided for compatibility only, and will be deleted +in a future release. +See +.IR ar (5) +for more information. +.SH STANDARDS +The +.I ar +utility is expected to offer a superset of the POSIX 1003.2 functionality. +.SH "SEE ALSO" +ld(1), ranlib(1), strmode(3), ar(5) diff --git a/usr.bin/ar/ar.5.5 b/usr.bin/ar/ar.5.5 new file mode 100644 index 0000000..29c8f8c --- /dev/null +++ b/usr.bin/ar/ar.5.5 @@ -0,0 +1,145 @@ +.\" 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. +.\" +.\" @(#)ar.5.5 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt AR 5 +.Os +.Sh NAME +.Nm ar +.Nd archive (library) file format +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +The archive command +.Nm ar +combines several files into one. +Archives are mainly used as libraries of object files intended to be +loaded using the link-editor +.Xr ld 1 . +.Pp +A file created with +.Nm ar +begins with the ``magic'' string "!\en". +The rest of the archive is made up of objects, each of which is composed +of a header for a file, a possible file name, and the file contents. +The header is portable between machine architectures, and, if the file +contents are printable, the archive is itself printable. +.Pp +The header is made up of six variable length +.Tn ASCII +fields, followed by a +two character trailer. +The fields are the object name (16 characters), the file last modification +time (12 characters), the user and group id's (each 6 characters), the file +mode (8 characters) and the file size (10 characters). +All numeric fields are in decimal, except for the file mode which is in +octal. +.Pp +The modification time is the file +.Fa st_mtime +field, i.e., +.Dv CUT +seconds since +the epoch. +The user and group id's are the file +.Fa st_uid +and +.Fa st_gid +fields. +The file mode is the file +.Fa st_mode +field. +The file size is the file +.Fa st_size +field. +The two-byte trailer is the string "\`\en". +.Pp +Only the name field has any provision for overflow. +If any file name is more than 16 characters in length or contains an +embedded space, the string "#1/" followed by the +.Tn ASCII +length of the +name is written in the name field. +The file size (stored in the archive header) is incremented by the length +of the name. +The name is then written immediately following the archive header. +.Pp +Any unused characters in any of these fields are written as space +characters. +If any fields are their particular maximum number of characters in +length, there will be no separation between the fields. +.Pp +Objects in the archive are always an even number of bytes long; files +which are an odd number of bytes long are padded with a newline (``\en'') +character, although the size in the header does not reflect this. +.Sh SEE ALSO +.Xr ar 1 , +.Xr stat 2 +.Sh HISTORY +There have been at least four +.Nm ar +formats. +The first was denoted by the leading ``magic'' number 0177555 (stored as +type int). +These archives were almost certainly created on a 16-bit machine, and +contain headers made up of five fields. +The fields are the object name (8 characters), the file last modification +time (type long), the user id (type char), the file mode (type char) and +the file size (type unsigned int). +Files were padded to an even number of bytes. +.Pp +The second was denoted by the leading ``magic'' number 0177545 (stored as +type int). +These archives may have been created on either 16 or 32-bit machines, and +contain headers made up of six fields. +The fields are the object name (14 characters), the file last modification +time (type long), the user and group id's (each type char), the file mode +(type int) and the file size (type long). +Files were padded to an even number of bytes. +For more information on converting from this format see +.Xr arcv 8 . +.Pp +The current archive format (without support for long character names and +names with embedded spaces) was introduced in +.Bx 4.0 . +The headers were the same as the current format, with the exception that +names longer than 16 characters were truncated, and names with embedded +spaces (and often trailing spaces) were not supported. +It has been extended for these reasons, +as described above. +This format first appeared in 4.4BSD. +.Sh COMPATIBILITY +No archive format is currently specified by any standard. +.At V +has historically distributed archives in a different format from +all of the above. diff --git a/usr.bin/ar/ar.c b/usr.bin/ar/ar.c new file mode 100644 index 0000000..38089e8 --- /dev/null +++ b/usr.bin/ar/ar.c @@ -0,0 +1,237 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ar.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +CHDR chdr; +u_int options; +char *archive, *envtmp, *posarg, *posname; +static void badoptions __P((char *)); +static void usage __P((void)); + +/* + * main -- + * main basically uses getopt to parse options and calls the appropriate + * functions. Some hacks that let us be backward compatible with 4.3 ar + * option parsing and sanity checking. + */ +int +main(argc, argv) + int argc; + char **argv; +{ + int c; + char *p; + int (*fcall) __P((char **)); + + if (argc < 3) + usage(); + + /* + * Historic versions didn't require a '-' in front of the options. + * Fix it, if necessary. + */ + if (*argv[1] != '-') { + if (!(p = malloc((u_int)(strlen(argv[1]) + 2)))) + err(1, NULL); + *p = '-'; + (void)strcpy(p + 1, argv[1]); + argv[1] = p; + } + + while ((c = getopt(argc, argv, "abcdilmopqrTtuvx")) != EOF) { + switch(c) { + case 'a': + options |= AR_A; + break; + case 'b': + case 'i': + options |= AR_B; + break; + case 'c': + options |= AR_C; + break; + case 'd': + options |= AR_D; + fcall = delete; + break; + case 'l': /* not documented, compatibility only */ + envtmp = "."; + break; + case 'm': + options |= AR_M; + fcall = move; + break; + case 'o': + options |= AR_O; + break; + case 'p': + options |= AR_P; + fcall = print; + break; + case 'q': + options |= AR_Q; + fcall = append; + break; + case 'r': + options |= AR_R; + fcall = replace; + break; + case 'T': + options |= AR_TR; + break; + case 't': + options |= AR_T; + fcall = contents; + break; + case 'u': + options |= AR_U; + break; + case 'v': + options |= AR_V; + break; + case 'x': + options |= AR_X; + fcall = extract; + break; + default: + usage(); + } + } + + argv += optind; + argc -= optind; + + /* One of -dmpqrtx required. */ + if (!(options & (AR_D|AR_M|AR_P|AR_Q|AR_R|AR_T|AR_X))) { + warnx("one of options -dmpqrtx is required"); + usage(); + } + /* Only one of -a and -bi allowed. */ + if (options & AR_A && options & AR_B) { + warnx("only one of -a and -[bi] options allowed"); + usage(); + } + /* -ab require a position argument. */ + if (options & (AR_A|AR_B)) { + if (!(posarg = *argv++)) { + warnx("no position operand specified"); + usage(); + } + posname = rname(posarg); + } + /* -d only valid with -Tv. */ + if (options & AR_D && options & ~(AR_D|AR_TR|AR_V)) + badoptions("-d"); + /* -m only valid with -abiTv. */ + if (options & AR_M && options & ~(AR_A|AR_B|AR_M|AR_TR|AR_V)) + badoptions("-m"); + /* -p only valid with -Tv. */ + if (options & AR_P && options & ~(AR_P|AR_TR|AR_V)) + badoptions("-p"); + /* -q only valid with -cTv. */ + if (options & AR_Q && options & ~(AR_C|AR_Q|AR_TR|AR_V)) + badoptions("-q"); + /* -r only valid with -abcuTv. */ + if (options & AR_R && options & ~(AR_A|AR_B|AR_C|AR_R|AR_U|AR_TR|AR_V)) + badoptions("-r"); + /* -t only valid with -Tv. */ + if (options & AR_T && options & ~(AR_T|AR_TR|AR_V)) + badoptions("-t"); + /* -x only valid with -ouTv. */ + if (options & AR_X && options & ~(AR_O|AR_U|AR_TR|AR_V|AR_X)) + badoptions("-x"); + + if (!(archive = *argv++)) { + warnx("no archive specified"); + usage(); + } + + /* -dmqr require a list of archive elements. */ + if (options & (AR_D|AR_M|AR_Q|AR_R) && !*argv) { + warnx("no archive members specified"); + usage(); + } + + exit((*fcall)(argv)); +} + +static void +badoptions(arg) + char *arg; +{ + + warnx("illegal option combination for %s", arg); + usage(); +} + +static void +usage() +{ + + (void)fprintf(stderr, "usage: ar -d [-Tv] archive file ...\n"); + (void)fprintf(stderr, "\tar -m [-Tv] archive file ...\n"); + (void)fprintf(stderr, "\tar -m [-abiTv] position archive file ...\n"); + (void)fprintf(stderr, "\tar -p [-Tv] archive [file ...]\n"); + (void)fprintf(stderr, "\tar -q [-cTv] archive file ...\n"); + (void)fprintf(stderr, "\tar -r [-cuTv] archive file ...\n"); + (void)fprintf(stderr, "\tar -r [-abciuTv] position archive file ...\n"); + (void)fprintf(stderr, "\tar -t [-Tv] archive [file ...]\n"); + (void)fprintf(stderr, "\tar -x [-ouTv] archive [file ...]\n"); + exit(1); +} diff --git a/usr.bin/ar/archive.c b/usr.bin/ar/archive.c new file mode 100644 index 0000000..10897d9 --- /dev/null +++ b/usr.bin/ar/archive.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)archive.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +typedef struct ar_hdr HDR; +static char hb[sizeof(HDR) + 1]; /* real header */ + +int +open_archive(mode) + int mode; +{ + int created, fd, nr; + char buf[SARMAG]; + + created = 0; + if (mode & O_CREAT) { + mode |= O_EXCL; + if ((fd = open(archive, mode, DEFFILEMODE)) >= 0) { + /* POSIX.2 puts create message on stderr. */ + if (!(options & AR_C)) + warnx("creating archive %s", archive); + created = 1; + goto opened; + } + if (errno != EEXIST) + error(archive); + mode &= ~O_EXCL; + } + if ((fd = open(archive, mode, DEFFILEMODE)) < 0) + error(archive); + + /* + * Attempt to place a lock on the opened file - if we get an + * error then someone is already working on this library (or + * it's going across NFS). + */ +opened: if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP) + error(archive); + + /* + * If not created, O_RDONLY|O_RDWR indicates that it has to be + * in archive format. + */ + if (!created && + ((mode & O_ACCMODE) == O_RDONLY || (mode & O_ACCMODE) == O_RDWR)) { + if ((nr = read(fd, buf, SARMAG) != SARMAG)) { + if (nr >= 0) + badfmt(); + error(archive); + } else if (bcmp(buf, ARMAG, SARMAG)) + badfmt(); + } else if (write(fd, ARMAG, SARMAG) != SARMAG) + error(archive); + return (fd); +} + +void +close_archive(fd) + int fd; +{ + + (void)close(fd); /* Implicit unlock. */ +} + +/* Convert ar header field to an integer. */ +#define AR_ATOI(from, to, len, base) { \ + memmove(buf, from, len); \ + buf[len] = '\0'; \ + to = strtol(buf, (char **)NULL, base); \ +} + +/* + * get_arobj -- + * read the archive header for this member + */ +int +get_arobj(fd) + int fd; +{ + struct ar_hdr *hdr; + int len, nr; + char *p, buf[20]; + + nr = read(fd, hb, sizeof(HDR)); + if (nr != sizeof(HDR)) { + if (!nr) + return (0); + if (nr < 0) + error(archive); + badfmt(); + } + + hdr = (struct ar_hdr *)hb; + if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1)) + badfmt(); + + /* Convert the header into the internal format. */ +#define DECIMAL 10 +#define OCTAL 8 + + AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL); + AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL); + AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL); + AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL); + AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL); + + /* Leading spaces should never happen. */ + if (hdr->ar_name[0] == ' ') + badfmt(); + + /* + * Long name support. Set the "real" size of the file, and the + * long name flag/size. + */ + if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) { + chdr.lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1); + if (len <= 0 || len > MAXNAMLEN) + badfmt(); + nr = read(fd, chdr.name, len); + if (nr != len) { + if (nr < 0) + error(archive); + badfmt(); + } + chdr.name[len] = 0; + chdr.size -= len; + } else { + chdr.lname = 0; + memmove(chdr.name, hdr->ar_name, sizeof(hdr->ar_name)); + + /* Strip trailing spaces, null terminate. */ + for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p); + *++p = '\0'; + } + return (1); +} + +static int already_written; + +/* + * put_arobj -- + * Write an archive member to a file. + */ +void +put_arobj(cfp, sb) + CF *cfp; + struct stat *sb; +{ + int lname; + char *name; + struct ar_hdr *hdr; + off_t size; + + /* + * If passed an sb structure, reading a file from disk. Get stat(2) + * information, build a name and construct a header. (Files are named + * by their last component in the archive.) If not, then just write + * the last header read. + */ + if (sb) { + name = rname(cfp->rname); + (void)fstat(cfp->rfd, sb); + + /* + * If not truncating names and the name is too long or contains + * a space, use extended format 1. + */ + lname = strlen(name); + if (options & AR_TR) { + if (lname > OLDARMAXNAME) { + (void)fflush(stdout); + warnx("warning: %s truncated to %.*s\n", + name, OLDARMAXNAME, name); + (void)fflush(stderr); + } + (void)sprintf(hb, HDR3, name, sb->st_mtimespec.ts_sec, + sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size, + ARFMAG); + lname = 0; + } else if (lname > sizeof(hdr->ar_name) || strchr(name, ' ')) + (void)sprintf(hb, HDR1, AR_EFMT1, lname, + sb->st_mtimespec.ts_sec, sb->st_uid, sb->st_gid, + sb->st_mode, sb->st_size + lname, ARFMAG); + else { + lname = 0; + (void)sprintf(hb, HDR2, name, sb->st_mtimespec.ts_sec, + sb->st_uid, sb->st_gid, sb->st_mode, sb->st_size, + ARFMAG); + } + size = sb->st_size; + } else { + lname = chdr.lname; + name = chdr.name; + size = chdr.size; + } + + if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR)) + error(cfp->wname); + if (lname) { + if (write(cfp->wfd, name, lname) != lname) + error(cfp->wname); + already_written = lname; + } + copy_ar(cfp, size); + already_written = 0; +} + +/* + * copy_ar -- + * Copy size bytes from one file to another - taking care to handle the + * extra byte (for odd size files) when reading archives and writing an + * extra byte if necessary when adding files to archive. The length of + * the object is the long name plus the object itself; the variable + * already_written gets set if a long name was written. + * + * The padding is really unnecessary, and is almost certainly a remnant + * of early archive formats where the header included binary data which + * a PDP-11 required to start on an even byte boundary. (Or, perhaps, + * because 16-bit word addressed copies were faster?) Anyhow, it should + * have been ripped out long ago. + */ +void +copy_ar(cfp, size) + CF *cfp; + off_t size; +{ + static char pad = '\n'; + off_t sz; + int from, nr, nw, off, to; + char buf[8*1024]; + + if (!(sz = size)) + return; + + from = cfp->rfd; + to = cfp->wfd; + sz = size; + while (sz && (nr = read(from, buf, MIN(sz, sizeof(buf)))) > 0) { + sz -= nr; + for (off = 0; off < nr; nr -= off, off += nw) + if ((nw = write(to, buf + off, nr)) < 0) + error(cfp->wname); + } + if (sz) { + if (nr == 0) + badfmt(); + error(cfp->rname); + } + + if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) { + if (nr == 0) + badfmt(); + error(cfp->rname); + } + if (cfp->flags & WPAD && (size + already_written) & 1 && + write(to, &pad, 1) != 1) + error(cfp->wname); +} + +/* + * skip_arobj - + * Skip over an object -- taking care to skip the pad bytes. + */ +void +skip_arobj(fd) + int fd; +{ + off_t len; + + len = chdr.size + (chdr.size + chdr.lname & 1); + if (lseek(fd, len, SEEK_CUR) == (off_t)-1) + error(archive); +} diff --git a/usr.bin/ar/archive.h b/usr.bin/ar/archive.h new file mode 100644 index 0000000..23b391f --- /dev/null +++ b/usr.bin/ar/archive.h @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)archive.h 8.3 (Berkeley) 4/2/94 + */ + +/* Ar(1) options. */ +#define AR_A 0x0001 +#define AR_B 0x0002 +#define AR_C 0x0004 +#define AR_D 0x0008 +#define AR_M 0x0010 +#define AR_O 0x0020 +#define AR_P 0x0040 +#define AR_Q 0x0080 +#define AR_R 0x0100 +#define AR_T 0x0200 +#define AR_TR 0x0400 +#define AR_U 0x0800 +#define AR_V 0x1000 +#define AR_X 0x2000 +extern u_int options; + +/* Set up file copy. */ +#define SETCF(from, fromname, to, toname, pad) { \ + cf.rfd = from; \ + cf.rname = fromname; \ + cf.wfd = to; \ + cf.wname = toname; \ + cf.flags = pad; \ +} + +/* File copy structure. */ +typedef struct { + int rfd; /* read file descriptor */ + char *rname; /* read name */ + int wfd; /* write file descriptor */ + char *wname; /* write name */ +#define NOPAD 0x00 /* don't pad */ +#define RPAD 0x01 /* pad on reads */ +#define WPAD 0x02 /* pad on writes */ + u_int flags; /* pad flags */ +} CF; + +/* Header structure internal format. */ +typedef struct { + off_t size; /* size of the object in bytes */ + long date; /* date */ + int lname; /* size of the long name in bytes */ + int gid; /* group */ + int uid; /* owner */ + u_short mode; /* permissions */ + char name[MAXNAMLEN + 1]; /* name */ +} CHDR; + +/* Header format strings. */ +#define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10qd%2s" +#define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10qd%2s" + +#define OLDARMAXNAME 15 +#define HDR3 "%-16.15s%-12ld%-6u%-6u%-8o%-10qd%2s" + + +#include + +struct stat; + +void close_archive __P((int)); +void copy_ar __P((CF *, off_t)); +int get_arobj __P((int)); +int open_archive __P((int)); +void put_arobj __P((CF *, struct stat *)); +void skip_arobj __P((int)); diff --git a/usr.bin/ar/contents.c b/usr.bin/ar/contents.c new file mode 100644 index 0000000..b2db77a --- /dev/null +++ b/usr.bin/ar/contents.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)contents.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +/* + * contents -- + * Handles t[v] option - opens the archive and then reads headers, + * skipping member contents. + */ +int +contents(argv) + char **argv; +{ + int afd, all; + struct tm *tp; + char *file, buf[25]; + + afd = open_archive(O_RDONLY); + + for (all = !*argv; get_arobj(afd);) { + if (all) + file = chdr.name; + else if (!(file = files(argv))) + goto next; + if (options & AR_V) { + (void)strmode(chdr.mode, buf); + (void)printf("%s %6d/%-6d %8qd ", + buf + 1, chdr.uid, chdr.gid, chdr.size); + tp = localtime(&chdr.date); + (void)strftime(buf, sizeof(buf), "%b %e %H:%M %Y", tp); + (void)printf("%s %s\n", buf, file); + } else + (void)printf("%s\n", file); + if (!all && !*argv) + break; +next: skip_arobj(afd); + } + close_archive(afd); + + if (*argv) { + orphans(argv); + return (1); + } + return (0); +} diff --git a/usr.bin/ar/delete.c b/usr.bin/ar/delete.c new file mode 100644 index 0000000..1ef332f --- /dev/null +++ b/usr.bin/ar/delete.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)delete.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" +#include "pathnames.h" + +/*- + * delete -- + * Deletes named members from the archive. + */ +int +delete(argv) + char **argv; +{ + CF cf; + off_t size; + int afd, tfd; + char *file; + + afd = open_archive(O_RDWR); + tfd = tmp(); + + /* Read and write to an archive; pad on both. */ + SETCF(afd, archive, tfd, tname, RPAD|WPAD); + while (get_arobj(afd)) { + if (*argv && (file = files(argv))) { + if (options & AR_V) + (void)printf("d - %s\n", file); + skip_arobj(afd); + continue; + } + put_arobj(&cf, (struct stat *)NULL); + } + + size = lseek(tfd, (off_t)0, SEEK_CUR); + (void)lseek(tfd, (off_t)0, SEEK_SET); + (void)lseek(afd, (off_t)SARMAG, SEEK_SET); + SETCF(tfd, tname, afd, archive, NOPAD); + copy_ar(&cf, size); + (void)close(tfd); + (void)ftruncate(afd, size + SARMAG); + close_archive(afd); + + if (*argv) { + orphans(argv); + return (1); + } + return (0); +} diff --git a/usr.bin/ar/extern.h b/usr.bin/ar/extern.h new file mode 100644 index 0000000..a6d7d71 --- /dev/null +++ b/usr.bin/ar/extern.h @@ -0,0 +1,54 @@ +/*- + * 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. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + */ + +int append __P((char **)); +void badfmt __P((void)); +int compare __P((char *)); +int contents __P((char **)); +int delete __P((char **)); +void error __P((char *)); +int extract __P((char **)); +char *files __P((char **argv)); +int move __P((char **)); +void orphans __P((char **argv)); +int print __P((char **)); +int replace __P((char **)); +char *rname __P((char *)); +int tmp __P((void)); + +extern char *archive; +extern char *posarg, *posname; /* positioning file name */ +extern char *tname; /* temporary file "name" */ +extern CHDR chdr; /* converted header */ diff --git a/usr.bin/ar/extract.c b/usr.bin/ar/extract.c new file mode 100644 index 0000000..2cc1ea0 --- /dev/null +++ b/usr.bin/ar/extract.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)extract.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +/* + * extract -- + * Extract files from the named archive - if member names given only + * extract those members otherwise extract all members. If 'o' option + * selected modify date of newly created file to be same as archive + * members date otherwise date is time of extraction. Does not modify + * archive. + */ +int +extract(argv) + char **argv; +{ + char *file; + int afd, all, eval, tfd; + struct timeval tv[2]; + struct stat sb; + CF cf; + + eval = 0; + tv[0].tv_usec = tv[1].tv_usec = 0; + + afd = open_archive(O_RDONLY); + + /* Read from an archive, write to disk; pad on read. */ + SETCF(afd, archive, 0, 0, RPAD); + for (all = !*argv; get_arobj(afd);) { + if (all) + file = chdr.name; + else if (!(file = files(argv))) { + skip_arobj(afd); + continue; + } + + if (options & AR_U && !stat(file, &sb) && + sb.st_mtime > chdr.date) + continue; + + if ((tfd = open(file, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR)) < 0) { + warn("%s", file); + skip_arobj(afd); + eval = 1; + continue; + } + + if (options & AR_V) + (void)printf("x - %s\n", file); + + cf.wfd = tfd; + cf.wname = file; + copy_ar(&cf, chdr.size); + + if (fchmod(tfd, (short)chdr.mode)) { + warn("chmod: %s", file); + eval = 1; + } + if (options & AR_O) { + tv[0].tv_sec = tv[1].tv_sec = chdr.date; + if (utimes(file, tv)) { + warn("utimes: %s", file); + eval = 1; + } + } + (void)close(tfd); + if (!all && !*argv) + break; + } + close_archive(afd); + + if (*argv) { + orphans(argv); + return (1); + } + return (0); +} diff --git a/usr.bin/ar/misc.c b/usr.bin/ar/misc.c new file mode 100644 index 0000000..d182fa9 --- /dev/null +++ b/usr.bin/ar/misc.c @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" +#include "pathnames.h" + +char *tname = "temporary file"; /* temporary file "name" */ + +int +tmp() +{ + extern char *envtmp; + sigset_t set, oset; + static int first; + int fd; + char path[MAXPATHLEN]; + + if (!first && !envtmp) { + envtmp = getenv("TMPDIR"); + first = 1; + } + + if (envtmp) + (void)sprintf(path, "%s/%s", envtmp, _NAME_ARTMP); + else + strcpy(path, _PATH_ARTMP); + + sigfillset(&set); + (void)sigprocmask(SIG_BLOCK, &set, &oset); + if ((fd = mkstemp(path)) == -1) + error(tname); + (void)unlink(path); + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + return (fd); +} + +/* + * files -- + * See if the current file matches any file in the argument list; if it + * does, remove it from the argument list. + */ +char * +files(argv) + char **argv; +{ + char **list, *p; + + for (list = argv; *list; ++list) + if (compare(*list)) { + p = *list; + for (; list[0] = list[1]; ++list) + continue; + return (p); + } + return (NULL); +} + +void +orphans(argv) + char **argv; +{ + + for (; *argv; ++argv) + warnx("%s: not found in archive", *argv); +} + +char * +rname(path) + char *path; +{ + char *ind; + + return ((ind = strrchr(path, '/')) ? ind + 1 : path); +} + +int +compare(dest) + char *dest; +{ + + if (options & AR_TR) + return (!strncmp(chdr.name, rname(dest), OLDARMAXNAME)); + return (!strcmp(chdr.name, rname(dest))); +} + +void +badfmt() +{ + + errx(1, "%s: %s", archive, strerror(EFTYPE)); +} + +void +error(name) + char *name; +{ + + errx(1, "%s", name); +} diff --git a/usr.bin/ar/move.c b/usr.bin/ar/move.c new file mode 100644 index 0000000..1bbdef4 --- /dev/null +++ b/usr.bin/ar/move.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)move.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" +#include "pathnames.h" + +/* + * move -- + * Change location of named members in archive - if 'b' or 'i' option + * selected then named members are placed before 'posname'. If 'a' + * option selected members go after 'posname'. If no options, members + * are moved to end of archive. + */ +int +move(argv) + char **argv; +{ + CF cf; + off_t size, tsize; + int afd, curfd, mods, tfd1, tfd2, tfd3; + char *file; + + afd = open_archive(O_RDWR); + mods = options & (AR_A|AR_B); + + tfd1 = tmp(); /* Files before key file. */ + tfd2 = tmp(); /* Files selected by user. */ + tfd3 = tmp(); /* Files after key file. */ + + /* + * Break archive into three parts -- selected entries and entries + * before and after the key entry. If positioning before the key, + * place the key at the beginning of the after key entries and if + * positioning after the key, place the key at the end of the before + * key entries. Put it all back together at the end. + */ + + /* Read and write to an archive; pad on both. */ + SETCF(afd, archive, 0, tname, RPAD|WPAD); + for (curfd = tfd1; get_arobj(afd);) { + if (*argv && (file = files(argv))) { + if (options & AR_V) + (void)printf("m - %s\n", file); + cf.wfd = tfd2; + put_arobj(&cf, (struct stat *)NULL); + continue; + } + if (mods && compare(posname)) { + mods = 0; + if (options & AR_B) + curfd = tfd3; + cf.wfd = curfd; + put_arobj(&cf, (struct stat *)NULL); + if (options & AR_A) + curfd = tfd3; + } else { + cf.wfd = curfd; + put_arobj(&cf, (struct stat *)NULL); + } + } + + if (mods) { + warnx("%s: archive member not found", posarg); + close_archive(afd); + return (1); + } + (void)lseek(afd, (off_t)SARMAG, SEEK_SET); + + SETCF(tfd1, tname, afd, archive, NOPAD); + tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR); + (void)lseek(tfd1, (off_t)0, SEEK_SET); + copy_ar(&cf, size); + + tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR); + (void)lseek(tfd2, (off_t)0, SEEK_SET); + cf.rfd = tfd2; + copy_ar(&cf, size); + + tsize += size = lseek(tfd3, (off_t)0, SEEK_CUR); + (void)lseek(tfd3, (off_t)0, SEEK_SET); + cf.rfd = tfd3; + copy_ar(&cf, size); + + (void)ftruncate(afd, tsize + SARMAG); + close_archive(afd); + + if (*argv) { + orphans(argv); + return (1); + } + return (0); +} diff --git a/usr.bin/ar/pathnames.h b/usr.bin/ar/pathnames.h new file mode 100644 index 0000000..ed92db6 --- /dev/null +++ b/usr.bin/ar/pathnames.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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 8.1 (Berkeley) 6/6/93 + */ + +#define _NAME_ARTMP "ar.XXXXXX" +#define _PATH_ARTMP "/tmp/ar.XXXXXX" diff --git a/usr.bin/ar/print.c b/usr.bin/ar/print.c new file mode 100644 index 0000000..4367628 --- /dev/null +++ b/usr.bin/ar/print.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)print.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +/* + * print -- + * Prints archive members on stdout - if member names given only + * print those members, otherwise print all members. + */ +int +print(argv) + char **argv; +{ + CF cf; + int afd, all; + char *file; + + afd = open_archive(O_RDONLY); + + /* Read from an archive, write to stdout; pad on read. */ + SETCF(afd, archive, STDOUT_FILENO, "stdout", RPAD); + for (all = !*argv; get_arobj(afd);) { + if (all) + file = chdr.name; + else if (!(file = files(argv))) { + skip_arobj(afd); + continue; + } + if (options & AR_V) { + (void)printf("\n<%s>\n\n", file); + (void)fflush(stdout); + } + copy_ar(&cf, chdr.size); + if (!all && !*argv) + break; + } + close_archive(afd); + + if (*argv) { + orphans(argv); + return (1); + } + return (0); +} diff --git a/usr.bin/ar/replace.c b/usr.bin/ar/replace.c new file mode 100644 index 0000000..cc12781 --- /dev/null +++ b/usr.bin/ar/replace.c @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)replace.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extern.h" + +/* + * replace -- + * Replace or add named members to archive. Entries already in the + * archive are swapped in place. Others are added before or after + * the key entry, based on the a, b and i options. If the u option + * is specified, modification dates select for replacement. + */ +int +replace(argv) + char **argv; +{ + char *file; + int afd, curfd, errflg, exists, mods, sfd, tfd1, tfd2; + struct stat sb; + CF cf; + off_t size, tsize; + + errflg = 0; + /* + * If doesn't exist, simply append to the archive. There's + * a race here, but it's pretty short, and not worth fixing. + */ + exists = !stat(archive, &sb); + afd = open_archive(O_CREAT|O_RDWR); + + if (!exists) { + tfd1 = -1; + tfd2 = tmp(); + goto append; + } + + tfd1 = tmp(); /* Files before key file. */ + tfd2 = tmp(); /* Files after key file. */ + + /* + * Break archive into two parts -- entries before and after the key + * entry. If positioning before the key, place the key at the + * beginning of the after key entries and if positioning after the + * key, place the key at the end of the before key entries. Put it + * all back together at the end. + */ + mods = (options & (AR_A|AR_B)); + for (curfd = tfd1; get_arobj(afd);) { + if (*argv && (file = files(argv))) { + if ((sfd = open(file, O_RDONLY)) < 0) { + errflg = 1; + warn("%s", file); + goto useold; + } + (void)fstat(sfd, &sb); + if (options & AR_U && sb.st_mtime <= chdr.date) + goto useold; + + if (options & AR_V) + (void)printf("r - %s\n", file); + + /* Read from disk, write to an archive; pad on write */ + SETCF(sfd, file, curfd, tname, WPAD); + put_arobj(&cf, &sb); + (void)close(sfd); + skip_arobj(afd); + continue; + } + + if (mods && compare(posname)) { + mods = 0; + if (options & AR_B) + curfd = tfd2; + /* Read and write to an archive; pad on both. */ + SETCF(afd, archive, curfd, tname, RPAD|WPAD); + put_arobj(&cf, (struct stat *)NULL); + if (options & AR_A) + curfd = tfd2; + } else { + /* Read and write to an archive; pad on both. */ +useold: SETCF(afd, archive, curfd, tname, RPAD|WPAD); + put_arobj(&cf, (struct stat *)NULL); + } + } + + if (mods) { + warnx("%s: archive member not found", posarg); + close_archive(afd); + return (1); + } + + /* Append any left-over arguments to the end of the after file. */ +append: while (file = *argv++) { + if (options & AR_V) + (void)printf("a - %s\n", file); + if ((sfd = open(file, O_RDONLY)) < 0) { + errflg = 1; + warn("%s", file); + continue; + } + (void)fstat(sfd, &sb); + /* Read from disk, write to an archive; pad on write. */ + SETCF(sfd, file, + options & (AR_A|AR_B) ? tfd1 : tfd2, tname, WPAD); + put_arobj(&cf, &sb); + (void)close(sfd); + } + + (void)lseek(afd, (off_t)SARMAG, SEEK_SET); + + SETCF(tfd1, tname, afd, archive, NOPAD); + if (tfd1 != -1) { + tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR); + (void)lseek(tfd1, (off_t)0, SEEK_SET); + copy_ar(&cf, size); + } else + tsize = 0; + + tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR); + (void)lseek(tfd2, (off_t)0, SEEK_SET); + cf.rfd = tfd2; + copy_ar(&cf, size); + + (void)ftruncate(afd, tsize + SARMAG); + close_archive(afd); + return (errflg); +} diff --git a/usr.bin/banner/Makefile b/usr.bin/banner/Makefile new file mode 100644 index 0000000..468368e --- /dev/null +++ b/usr.bin/banner/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= banner +MAN6= banner.0 + +.include diff --git a/usr.bin/banner/banner.6 b/usr.bin/banner/banner.6 new file mode 100644 index 0000000..3427a66 --- /dev/null +++ b/usr.bin/banner/banner.6 @@ -0,0 +1,72 @@ +.\" 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. +.\" +.\" @(#)banner.6 8.1 (Berkeley) 6/6/93 +.\" +.TH BANNER 6 "June 6, 1993" +.UC +.SH NAME +banner \- print large banner on printer +.SH SYNOPSIS +.B /usr/games/banner +[ +.BI \-w n +] +message ... +.SH DESCRIPTION +.I Banner +prints a large, high quality banner on the standard output. +If the message is omitted, it prompts for and +reads one line of its standard input. If +.B \-w +is given, the output is scrunched down from a width of 132 to +.I n , +suitable for a narrow terminal. If +.I n +is omitted, it defaults to 80. +.PP +The output should be printed on a hard-copy device, up to 132 columns wide, +with no breaks between the pages. The volume is great enough that you +may want +a printer or a fast hardcopy terminal, but if you are patient, a +decwriter or other 300 baud terminal will do. +.SH BUGS +Several ASCII characters are not defined, notably <, >, [, ], \\, +^, _, {, }, |, and ~. Also, the characters ", ', and & are funny +looking (but in a useful way.) +.PP +The +.B \-w +option is implemented by skipping some rows and columns. +The smaller it gets, the grainier the output. +Sometimes it runs letters together. +.SH AUTHOR +Mark Horton diff --git a/usr.bin/banner/banner.c b/usr.bin/banner/banner.c new file mode 100644 index 0000000..6c8e560 --- /dev/null +++ b/usr.bin/banner/banner.c @@ -0,0 +1,1160 @@ +/* + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)banner.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * banner - prints large signs + * banner [-w#] [-d] [-t] message ... + */ + +#include +#include +#include +#include +#include + +#define MAXMSG 1024 +#define DWIDTH 132 +#define NCHARS 128 +#define NBYTES 9271 + +/* Pointers into data_table for each ASCII char */ +int asc_ptr[NCHARS] = { +/* ^@ */ 0, 0, 0, 0, 0, 0, 0, 0, +/* ^H */ 0, 0, 0, 0, 0, 0, 0, 0, +/* ^P */ 0, 0, 0, 0, 0, 0, 0, 0, +/* ^X */ 0, 0, 0, 0, 0, 0, 0, 0, +/* */ 1, 3, 50, 81, 104, 281, 483, 590, +/* ( */ 621, 685, 749, 851, 862, 893, 898, 921, +/* 0 */1019, 1150, 1200, 1419, 1599, 1744, 1934, 2111, +/* 8 */2235, 2445, 2622, 2659, 0, 2708, 0, 2715, +/* @ */2857, 3072, 3273, 3403, 3560, 3662, 3730, 3785, +/* H */3965, 4000, 4015, 4115, 4281, 4314, 4432, 4548, +/* P */4709, 4790, 4999, 5188, 5397, 5448, 5576, 5710, +/* X */5892, 6106, 6257, 0, 0, 0, 0, 0, +/* ` */ 50, 6503, 6642, 6733, 6837, 6930, 7073, 7157, +/* h */7380, 7452, 7499, 7584, 7689, 7702, 7797, 7869, +/* p */7978, 8069, 8160, 8222, 8381, 8442, 8508, 8605, +/* x */8732, 8888, 9016, 0, 0, 0, 0, 0 +}; + +/* + * Table of stuff to print. Format: + * 128+n -> print current line n times. + * 64+n -> this is last byte of char. + * else, put m chars at position n (where m + * is the next elt in array) and goto second + * next element in array. + */ +char data_table[NBYTES] = { +/* 0 1 2 3 4 5 6 7 8 9 */ +/* 0 */ 129, 227, 130, 34, 6, 90, 19, 129, 32, 10, +/* 10 */ 74, 40, 129, 31, 12, 64, 53, 129, 30, 14, +/* 20 */ 54, 65, 129, 30, 14, 53, 67, 129, 30, 14, +/* 30 */ 54, 65, 129, 31, 12, 64, 53, 129, 32, 10, +/* 40 */ 74, 40, 129, 34, 6, 90, 19, 129, 194, 130, +/* 50 */ 99, 9, 129, 97, 14, 129, 96, 18, 129, 95, +/* 60 */ 22, 129, 95, 16, 117, 2, 129, 95, 14, 129, +/* 70 */ 96, 11, 129, 97, 9, 129, 99, 6, 129, 194, +/* 80 */ 129, 87, 4, 101, 4, 131, 82, 28, 131, 87, +/* 90 */ 4, 101, 4, 133, 82, 28, 131, 87, 4, 101, +/* 100 */ 4, 131, 193, 129, 39, 1, 84, 27, 129, 38, +/* 110 */ 3, 81, 32, 129, 37, 5, 79, 35, 129, 36, +/* 120 */ 5, 77, 38, 129, 35, 5, 76, 40, 129, 34, +/* 130 */ 5, 75, 21, 103, 14, 129, 33, 5, 74, 19, +/* 140 */ 107, 11, 129, 32, 5, 73, 17, 110, 9, 129, +/* 150 */ 32, 4, 73, 16, 112, 7, 129, 31, 4, 72, +/* 160 */ 15, 114, 6, 129, 31, 4, 72, 14, 115, 5, +/* 170 */ 129, 30, 4, 71, 15, 116, 5, 129, 27, 97, +/* 180 */ 131, 30, 4, 69, 14, 117, 4, 129, 30, 4, +/* 190 */ 68, 15, 117, 4, 132, 30, 4, 68, 14, 117, +/* 200 */ 4, 129, 27, 97, 131, 30, 5, 65, 15, 116, +/* 210 */ 5, 129, 31, 4, 65, 14, 116, 4, 129, 31, +/* 220 */ 6, 64, 15, 116, 4, 129, 32, 7, 62, 16, +/* 230 */ 115, 4, 129, 32, 9, 61, 17, 114, 5, 129, +/* 240 */ 33, 11, 58, 19, 113, 5, 129, 34, 14, 55, +/* 250 */ 21, 112, 5, 129, 35, 40, 111, 5, 129, 36, +/* 260 */ 38, 110, 5, 129, 37, 35, 109, 5, 129, 38, +/* 270 */ 32, 110, 3, 129, 40, 27, 111, 1, 129, 193, +/* 280 */ 129, 30, 4, 103, 9, 129, 30, 7, 100, 15, +/* 290 */ 129, 30, 10, 99, 17, 129, 33, 10, 97, 6, +/* 300 */ 112, 6, 129, 36, 10, 96, 5, 114, 5, 129, +/* 310 */ 39, 10, 96, 4, 115, 4, 129, 42, 10, 95, +/* 320 */ 4, 116, 4, 129, 45, 10, 95, 3, 117, 3, +/* 330 */ 129, 48, 10, 95, 3, 117, 3, 129, 51, 10, +/* 340 */ 95, 4, 116, 4, 129, 54, 10, 96, 4, 115, +/* 350 */ 4, 129, 57, 10, 96, 5, 114, 5, 129, 60, +/* 360 */ 10, 97, 6, 112, 6, 129, 63, 10, 99, 17, +/* 370 */ 129, 66, 10, 100, 15, 129, 69, 10, 103, 9, +/* 380 */ 129, 39, 9, 72, 10, 129, 36, 15, 75, 10, +/* 390 */ 129, 35, 17, 78, 10, 129, 33, 6, 48, 6, +/* 400 */ 81, 10, 129, 32, 5, 50, 5, 84, 10, 129, +/* 410 */ 32, 4, 51, 4, 87, 10, 129, 31, 4, 52, +/* 420 */ 4, 90, 10, 129, 31, 3, 53, 3, 93, 10, +/* 430 */ 129, 31, 3, 53, 3, 96, 10, 129, 31, 4, +/* 440 */ 52, 4, 99, 10, 129, 32, 4, 51, 4, 102, +/* 450 */ 10, 129, 32, 5, 50, 5, 105, 10, 129, 33, +/* 460 */ 6, 48, 6, 108, 10, 129, 35, 17, 111, 10, +/* 470 */ 129, 36, 15, 114, 7, 129, 40, 9, 118, 4, +/* 480 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41, +/* 490 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44, +/* 500 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32, +/* 510 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31, +/* 520 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30, +/* 530 */ 5, 79, 5, 129, 20, 74, 132, 30, 4, 80, +/* 540 */ 4, 129, 31, 3, 79, 4, 129, 31, 4, 79, +/* 550 */ 4, 129, 32, 3, 78, 4, 129, 32, 4, 76, +/* 560 */ 6, 129, 33, 4, 74, 7, 129, 34, 4, 72, +/* 570 */ 8, 129, 35, 5, 72, 7, 129, 37, 5, 73, +/* 580 */ 4, 129, 39, 4, 74, 1, 129, 129, 193, 130, +/* 590 */ 111, 6, 129, 109, 10, 129, 108, 12, 129, 107, +/* 600 */ 14, 129, 97, 2, 105, 16, 129, 99, 22, 129, +/* 610 */ 102, 18, 129, 105, 14, 129, 108, 9, 129, 194, +/* 620 */ 130, 63, 25, 129, 57, 37, 129, 52, 47, 129, +/* 630 */ 48, 55, 129, 44, 63, 129, 41, 69, 129, 38, +/* 640 */ 75, 129, 36, 79, 129, 34, 83, 129, 33, 28, +/* 650 */ 90, 28, 129, 32, 23, 96, 23, 129, 32, 17, +/* 660 */ 102, 17, 129, 31, 13, 107, 13, 129, 30, 9, +/* 670 */ 112, 9, 129, 30, 5, 116, 5, 129, 30, 1, +/* 680 */ 120, 1, 129, 194, 130, 30, 1, 120, 1, 129, +/* 690 */ 30, 5, 116, 5, 129, 30, 9, 112, 9, 129, +/* 700 */ 31, 13, 107, 13, 129, 32, 17, 102, 17, 129, +/* 710 */ 32, 23, 96, 23, 129, 33, 28, 90, 28, 129, +/* 720 */ 34, 83, 129, 36, 79, 129, 38, 75, 129, 41, +/* 730 */ 69, 129, 44, 63, 129, 48, 55, 129, 52, 47, +/* 740 */ 129, 57, 37, 129, 63, 25, 129, 194, 129, 80, +/* 750 */ 4, 130, 80, 4, 129, 68, 2, 80, 4, 94, +/* 760 */ 2, 129, 66, 6, 80, 4, 92, 6, 129, 67, +/* 770 */ 7, 80, 4, 90, 7, 129, 69, 7, 80, 4, +/* 780 */ 88, 7, 129, 71, 6, 80, 4, 87, 6, 129, +/* 790 */ 72, 20, 129, 74, 16, 129, 76, 12, 129, 62, +/* 800 */ 40, 131, 76, 12, 129, 74, 16, 129, 72, 20, +/* 810 */ 129, 71, 6, 80, 4, 87, 6, 129, 69, 7, +/* 820 */ 80, 4, 88, 7, 129, 67, 7, 80, 4, 90, +/* 830 */ 7, 129, 66, 6, 80, 4, 92, 6, 129, 68, +/* 840 */ 2, 80, 4, 94, 2, 129, 80, 4, 130, 193, +/* 850 */ 129, 60, 4, 139, 41, 42, 131, 60, 4, 139, +/* 860 */ 193, 130, 34, 6, 129, 32, 10, 129, 31, 12, +/* 870 */ 129, 30, 14, 129, 20, 2, 28, 16, 129, 22, +/* 880 */ 22, 129, 24, 19, 129, 27, 15, 129, 31, 9, +/* 890 */ 129, 194, 129, 60, 4, 152, 193, 130, 34, 6, +/* 900 */ 129, 32, 10, 129, 31, 12, 129, 30, 14, 131, +/* 910 */ 31, 12, 129, 32, 10, 129, 34, 6, 129, 194, +/* 920 */ 129, 30, 4, 129, 30, 7, 129, 30, 10, 129, +/* 930 */ 33, 10, 129, 36, 10, 129, 39, 10, 129, 42, +/* 940 */ 10, 129, 45, 10, 129, 48, 10, 129, 51, 10, +/* 950 */ 129, 54, 10, 129, 57, 10, 129, 60, 10, 129, +/* 960 */ 63, 10, 129, 66, 10, 129, 69, 10, 129, 72, +/* 970 */ 10, 129, 75, 10, 129, 78, 10, 129, 81, 10, +/* 980 */ 129, 84, 10, 129, 87, 10, 129, 90, 10, 129, +/* 990 */ 93, 10, 129, 96, 10, 129, 99, 10, 129, 102, +/* 1000 */ 10, 129, 105, 10, 129, 108, 10, 129, 111, 10, +/* 1010 */ 129, 114, 7, 129, 117, 4, 129, 193, 129, 60, +/* 1020 */ 31, 129, 53, 45, 129, 49, 53, 129, 46, 59, +/* 1030 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129, +/* 1040 */ 37, 77, 129, 36, 79, 129, 35, 15, 101, 15, +/* 1050 */ 129, 34, 11, 106, 11, 129, 33, 9, 109, 9, +/* 1060 */ 129, 32, 7, 112, 7, 129, 31, 6, 114, 6, +/* 1070 */ 129, 31, 5, 115, 5, 129, 30, 5, 116, 5, +/* 1080 */ 129, 30, 4, 117, 4, 132, 30, 5, 116, 5, +/* 1090 */ 129, 31, 5, 115, 5, 129, 31, 6, 114, 6, +/* 1100 */ 129, 32, 7, 112, 7, 129, 33, 9, 109, 9, +/* 1110 */ 129, 34, 11, 106, 11, 129, 35, 15, 101, 15, +/* 1120 */ 129, 36, 79, 129, 37, 77, 129, 39, 73, 129, +/* 1130 */ 41, 69, 129, 43, 65, 129, 46, 59, 129, 49, +/* 1140 */ 53, 129, 53, 45, 129, 60, 31, 129, 193, 129, +/* 1150 */ 30, 4, 129, 30, 4, 100, 1, 129, 30, 4, +/* 1160 */ 100, 3, 129, 30, 4, 100, 5, 129, 30, 76, +/* 1170 */ 129, 30, 78, 129, 30, 80, 129, 30, 82, 129, +/* 1180 */ 30, 83, 129, 30, 85, 129, 30, 87, 129, 30, +/* 1190 */ 89, 129, 30, 91, 129, 30, 4, 132, 193, 129, +/* 1200 */ 30, 3, 129, 30, 7, 129, 30, 10, 112, 1, +/* 1210 */ 129, 30, 13, 112, 2, 129, 30, 16, 112, 3, +/* 1220 */ 129, 30, 18, 111, 5, 129, 30, 21, 111, 6, +/* 1230 */ 129, 30, 23, 112, 6, 129, 30, 14, 47, 8, +/* 1240 */ 113, 6, 129, 30, 14, 49, 8, 114, 5, 129, +/* 1250 */ 30, 14, 51, 8, 115, 5, 129, 30, 14, 53, +/* 1260 */ 8, 116, 4, 129, 30, 14, 55, 8, 116, 5, +/* 1270 */ 129, 30, 14, 56, 9, 117, 4, 129, 30, 14, +/* 1280 */ 57, 9, 117, 4, 129, 30, 14, 58, 10, 117, +/* 1290 */ 4, 129, 30, 14, 59, 10, 117, 4, 129, 30, +/* 1300 */ 14, 60, 11, 117, 4, 129, 30, 14, 61, 11, +/* 1310 */ 116, 5, 129, 30, 14, 62, 11, 116, 5, 129, +/* 1320 */ 30, 14, 63, 12, 115, 6, 129, 30, 14, 64, +/* 1330 */ 13, 114, 7, 129, 30, 14, 65, 13, 113, 8, +/* 1340 */ 129, 30, 14, 65, 15, 111, 9, 129, 30, 14, +/* 1350 */ 66, 16, 109, 11, 129, 30, 14, 67, 17, 107, +/* 1360 */ 12, 129, 30, 14, 68, 20, 103, 16, 129, 30, +/* 1370 */ 14, 69, 49, 129, 30, 14, 70, 47, 129, 30, +/* 1380 */ 14, 71, 45, 129, 30, 14, 73, 42, 129, 30, +/* 1390 */ 15, 75, 38, 129, 33, 12, 77, 34, 129, 36, +/* 1400 */ 10, 79, 30, 129, 40, 6, 82, 23, 129, 44, +/* 1410 */ 3, 86, 15, 129, 47, 1, 129, 193, 129, 129, +/* 1420 */ 38, 3, 129, 37, 5, 111, 1, 129, 36, 7, +/* 1430 */ 111, 2, 129, 35, 9, 110, 5, 129, 34, 8, +/* 1440 */ 110, 6, 129, 33, 7, 109, 8, 129, 32, 7, +/* 1450 */ 110, 8, 129, 32, 6, 112, 7, 129, 31, 6, +/* 1460 */ 113, 6, 129, 31, 5, 114, 6, 129, 30, 5, +/* 1470 */ 115, 5, 129, 30, 5, 116, 4, 129, 30, 4, +/* 1480 */ 117, 4, 131, 30, 4, 117, 4, 129, 30, 4, +/* 1490 */ 79, 2, 117, 4, 129, 30, 5, 78, 4, 117, +/* 1500 */ 4, 129, 30, 5, 77, 6, 116, 5, 129, 30, +/* 1510 */ 6, 76, 8, 115, 6, 129, 30, 7, 75, 11, +/* 1520 */ 114, 6, 129, 30, 8, 73, 15, 112, 8, 129, +/* 1530 */ 31, 9, 71, 19, 110, 9, 129, 31, 11, 68, +/* 1540 */ 26, 107, 12, 129, 32, 13, 65, 14, 82, 36, +/* 1550 */ 129, 32, 16, 61, 17, 83, 34, 129, 33, 44, +/* 1560 */ 84, 32, 129, 34, 42, 85, 30, 129, 35, 40, +/* 1570 */ 87, 27, 129, 36, 38, 89, 23, 129, 38, 34, +/* 1580 */ 92, 17, 129, 40, 30, 95, 11, 129, 42, 26, +/* 1590 */ 129, 45, 20, 129, 49, 11, 129, 193, 129, 49, +/* 1600 */ 1, 129, 49, 4, 129, 49, 6, 129, 49, 8, +/* 1610 */ 129, 49, 10, 129, 49, 12, 129, 49, 14, 129, +/* 1620 */ 49, 17, 129, 49, 19, 129, 49, 21, 129, 49, +/* 1630 */ 23, 129, 49, 14, 65, 9, 129, 49, 14, 67, +/* 1640 */ 9, 129, 49, 14, 69, 9, 129, 49, 14, 71, +/* 1650 */ 10, 129, 49, 14, 74, 9, 129, 49, 14, 76, +/* 1660 */ 9, 129, 49, 14, 78, 9, 129, 49, 14, 80, +/* 1670 */ 9, 129, 49, 14, 82, 9, 129, 49, 14, 84, +/* 1680 */ 9, 129, 30, 4, 49, 14, 86, 10, 129, 30, +/* 1690 */ 4, 49, 14, 89, 9, 129, 30, 4, 49, 14, +/* 1700 */ 91, 9, 129, 30, 4, 49, 14, 93, 9, 129, +/* 1710 */ 30, 74, 129, 30, 76, 129, 30, 78, 129, 30, +/* 1720 */ 81, 129, 30, 83, 129, 30, 85, 129, 30, 87, +/* 1730 */ 129, 30, 89, 129, 30, 91, 129, 30, 4, 49, +/* 1740 */ 14, 132, 193, 129, 37, 1, 129, 36, 3, 77, +/* 1750 */ 3, 129, 35, 5, 78, 11, 129, 34, 7, 78, +/* 1760 */ 21, 129, 33, 7, 79, 29, 129, 32, 7, 79, +/* 1770 */ 38, 129, 32, 6, 80, 4, 92, 29, 129, 31, +/* 1780 */ 6, 80, 5, 102, 19, 129, 31, 5, 80, 6, +/* 1790 */ 107, 14, 129, 31, 4, 81, 5, 107, 14, 129, +/* 1800 */ 30, 5, 81, 6, 107, 14, 129, 30, 4, 81, +/* 1810 */ 6, 107, 14, 130, 30, 4, 81, 7, 107, 14, +/* 1820 */ 129, 30, 4, 80, 8, 107, 14, 130, 30, 5, +/* 1830 */ 80, 8, 107, 14, 129, 30, 5, 79, 9, 107, +/* 1840 */ 14, 129, 31, 5, 79, 9, 107, 14, 129, 31, +/* 1850 */ 6, 78, 10, 107, 14, 129, 32, 6, 76, 11, +/* 1860 */ 107, 14, 129, 32, 8, 74, 13, 107, 14, 129, +/* 1870 */ 33, 10, 71, 16, 107, 14, 129, 33, 15, 67, +/* 1880 */ 19, 107, 14, 129, 34, 51, 107, 14, 129, 35, +/* 1890 */ 49, 107, 14, 129, 36, 47, 107, 14, 129, 37, +/* 1900 */ 45, 107, 14, 129, 39, 41, 107, 14, 129, 41, +/* 1910 */ 37, 107, 14, 129, 44, 32, 107, 14, 129, 47, +/* 1920 */ 25, 111, 10, 129, 51, 16, 115, 6, 129, 119, +/* 1930 */ 2, 129, 193, 129, 56, 39, 129, 51, 49, 129, +/* 1940 */ 47, 57, 129, 44, 63, 129, 42, 67, 129, 40, +/* 1950 */ 71, 129, 38, 75, 129, 37, 77, 129, 35, 81, +/* 1960 */ 129, 34, 16, 74, 5, 101, 16, 129, 33, 11, +/* 1970 */ 76, 5, 107, 11, 129, 32, 9, 77, 5, 110, +/* 1980 */ 9, 129, 32, 7, 79, 4, 112, 7, 129, 31, +/* 1990 */ 6, 80, 4, 114, 6, 129, 31, 5, 81, 4, +/* 2000 */ 115, 5, 129, 30, 5, 82, 4, 116, 5, 129, +/* 2010 */ 30, 4, 82, 4, 116, 5, 129, 30, 4, 82, +/* 2020 */ 5, 117, 4, 131, 30, 5, 82, 5, 117, 4, +/* 2030 */ 129, 31, 5, 81, 6, 117, 4, 129, 31, 6, +/* 2040 */ 80, 7, 117, 4, 129, 32, 7, 79, 8, 117, +/* 2050 */ 4, 129, 32, 9, 77, 9, 116, 5, 129, 33, +/* 2060 */ 11, 75, 11, 116, 4, 129, 34, 16, 69, 16, +/* 2070 */ 115, 5, 129, 35, 49, 114, 5, 129, 37, 46, +/* 2080 */ 113, 5, 129, 38, 44, 112, 6, 129, 40, 41, +/* 2090 */ 112, 5, 129, 42, 37, 113, 3, 129, 44, 33, +/* 2100 */ 114, 1, 129, 47, 27, 129, 51, 17, 129, 193, +/* 2110 */ 129, 103, 2, 129, 103, 6, 129, 104, 9, 129, +/* 2120 */ 105, 12, 129, 106, 15, 129, 107, 14, 135, 30, +/* 2130 */ 10, 107, 14, 129, 30, 17, 107, 14, 129, 30, +/* 2140 */ 25, 107, 14, 129, 30, 31, 107, 14, 129, 30, +/* 2150 */ 37, 107, 14, 129, 30, 42, 107, 14, 129, 30, +/* 2160 */ 46, 107, 14, 129, 30, 50, 107, 14, 129, 30, +/* 2170 */ 54, 107, 14, 129, 30, 58, 107, 14, 129, 59, +/* 2180 */ 32, 107, 14, 129, 64, 30, 107, 14, 129, 74, +/* 2190 */ 23, 107, 14, 129, 81, 18, 107, 14, 129, 86, +/* 2200 */ 16, 107, 14, 129, 91, 14, 107, 14, 129, 96, +/* 2210 */ 25, 129, 100, 21, 129, 104, 17, 129, 107, 14, +/* 2220 */ 129, 111, 10, 129, 114, 7, 129, 117, 4, 129, +/* 2230 */ 120, 1, 129, 193, 129, 48, 13, 129, 44, 21, +/* 2240 */ 129, 42, 26, 129, 40, 30, 92, 12, 129, 38, +/* 2250 */ 34, 88, 20, 129, 36, 37, 86, 25, 129, 35, +/* 2260 */ 39, 84, 29, 129, 34, 13, 63, 12, 82, 33, +/* 2270 */ 129, 33, 11, 67, 9, 80, 36, 129, 32, 9, +/* 2280 */ 70, 7, 79, 38, 129, 31, 8, 72, 46, 129, +/* 2290 */ 30, 7, 74, 22, 108, 11, 129, 30, 6, 75, +/* 2300 */ 19, 111, 9, 129, 30, 5, 75, 17, 113, 7, +/* 2310 */ 129, 30, 5, 74, 16, 114, 6, 129, 30, 4, +/* 2320 */ 73, 16, 115, 6, 129, 30, 4, 72, 16, 116, +/* 2330 */ 5, 129, 30, 4, 72, 15, 117, 4, 129, 30, +/* 2340 */ 4, 71, 16, 117, 4, 129, 30, 5, 70, 16, +/* 2350 */ 117, 4, 129, 30, 5, 70, 15, 117, 4, 129, +/* 2360 */ 30, 6, 69, 15, 116, 5, 129, 30, 7, 68, +/* 2370 */ 17, 115, 5, 129, 30, 9, 67, 19, 114, 6, +/* 2380 */ 129, 30, 10, 65, 22, 113, 6, 129, 31, 12, +/* 2390 */ 63, 27, 110, 9, 129, 32, 14, 60, 21, 84, +/* 2400 */ 9, 106, 12, 129, 33, 47, 85, 32, 129, 34, +/* 2410 */ 45, 86, 30, 129, 35, 43, 88, 26, 129, 36, +/* 2420 */ 40, 90, 22, 129, 38, 36, 93, 17, 129, 40, +/* 2430 */ 32, 96, 10, 129, 42, 28, 129, 44, 23, 129, +/* 2440 */ 48, 15, 129, 193, 129, 83, 17, 129, 77, 27, +/* 2450 */ 129, 36, 1, 74, 33, 129, 35, 3, 72, 37, +/* 2460 */ 129, 34, 5, 70, 41, 129, 33, 6, 69, 44, +/* 2470 */ 129, 33, 5, 68, 46, 129, 32, 5, 67, 49, +/* 2480 */ 129, 31, 5, 66, 17, 101, 16, 129, 31, 5, +/* 2490 */ 66, 11, 108, 10, 129, 30, 4, 65, 9, 110, +/* 2500 */ 9, 129, 30, 4, 64, 8, 112, 7, 129, 30, +/* 2510 */ 4, 64, 7, 114, 6, 129, 30, 4, 64, 6, +/* 2520 */ 115, 5, 129, 30, 4, 64, 5, 116, 5, 129, +/* 2530 */ 30, 4, 64, 5, 117, 4, 131, 30, 4, 65, +/* 2540 */ 4, 117, 4, 129, 30, 5, 65, 4, 116, 5, +/* 2550 */ 129, 31, 5, 66, 4, 115, 5, 129, 31, 6, +/* 2560 */ 67, 4, 114, 6, 129, 32, 7, 68, 4, 112, +/* 2570 */ 7, 129, 32, 9, 69, 5, 110, 9, 129, 33, +/* 2580 */ 11, 70, 5, 107, 11, 129, 34, 16, 72, 5, +/* 2590 */ 101, 16, 129, 35, 81, 129, 37, 77, 129, 38, +/* 2600 */ 75, 129, 40, 71, 129, 42, 67, 129, 44, 63, +/* 2610 */ 129, 47, 57, 129, 51, 49, 129, 56, 39, 129, +/* 2620 */ 193, 130, 34, 6, 74, 6, 129, 32, 10, 72, +/* 2630 */ 10, 129, 31, 12, 71, 12, 129, 30, 14, 70, +/* 2640 */ 14, 131, 31, 12, 71, 12, 129, 32, 10, 72, +/* 2650 */ 10, 129, 34, 6, 74, 6, 129, 194, 130, 34, +/* 2660 */ 6, 74, 6, 129, 32, 10, 72, 10, 129, 31, +/* 2670 */ 12, 71, 12, 129, 30, 14, 70, 14, 129, 20, +/* 2680 */ 2, 28, 16, 70, 14, 129, 22, 22, 70, 14, +/* 2690 */ 129, 24, 19, 71, 12, 129, 27, 15, 72, 10, +/* 2700 */ 129, 31, 9, 74, 6, 129, 194, 129, 53, 4, +/* 2710 */ 63, 4, 152, 193, 130, 99, 7, 129, 97, 13, +/* 2720 */ 129, 96, 16, 129, 96, 18, 129, 96, 19, 129, +/* 2730 */ 97, 19, 129, 99, 6, 110, 7, 129, 112, 6, +/* 2740 */ 129, 114, 5, 129, 34, 6, 57, 5, 115, 4, +/* 2750 */ 129, 32, 10, 54, 12, 116, 4, 129, 31, 12, +/* 2760 */ 53, 16, 117, 3, 129, 30, 14, 52, 20, 117, +/* 2770 */ 4, 129, 30, 14, 52, 23, 117, 4, 129, 30, +/* 2780 */ 14, 52, 25, 117, 4, 129, 31, 12, 52, 27, +/* 2790 */ 117, 4, 129, 32, 10, 53, 10, 70, 11, 116, +/* 2800 */ 5, 129, 34, 6, 55, 5, 73, 10, 115, 6, +/* 2810 */ 129, 74, 11, 114, 7, 129, 75, 12, 112, 9, +/* 2820 */ 129, 76, 13, 110, 10, 129, 77, 16, 106, 14, +/* 2830 */ 129, 78, 41, 129, 80, 38, 129, 81, 36, 129, +/* 2840 */ 82, 34, 129, 84, 30, 129, 86, 26, 129, 88, +/* 2850 */ 22, 129, 92, 14, 129, 194, 129, 55, 15, 129, +/* 2860 */ 50, 25, 129, 47, 32, 129, 45, 13, 70, 12, +/* 2870 */ 129, 43, 9, 76, 10, 129, 42, 6, 79, 8, +/* 2880 */ 129, 41, 5, 81, 7, 129, 40, 4, 84, 6, +/* 2890 */ 129, 39, 4, 59, 12, 85, 6, 129, 38, 4, +/* 2900 */ 55, 19, 87, 5, 129, 37, 4, 53, 23, 88, +/* 2910 */ 4, 129, 36, 4, 51, 8, 71, 6, 89, 4, +/* 2920 */ 129, 36, 4, 51, 6, 73, 4, 89, 4, 129, +/* 2930 */ 36, 4, 50, 6, 74, 4, 90, 3, 129, 35, +/* 2940 */ 4, 50, 5, 75, 3, 90, 4, 129, 35, 4, +/* 2950 */ 50, 4, 75, 4, 90, 4, 131, 35, 4, 50, +/* 2960 */ 5, 75, 4, 90, 4, 129, 36, 4, 51, 5, +/* 2970 */ 75, 4, 90, 4, 129, 36, 4, 51, 6, 75, +/* 2980 */ 4, 90, 4, 129, 36, 4, 53, 26, 90, 4, +/* 2990 */ 129, 37, 4, 54, 25, 90, 4, 129, 37, 4, +/* 3000 */ 52, 27, 90, 3, 129, 38, 4, 52, 4, 89, +/* 3010 */ 4, 129, 39, 4, 51, 4, 88, 4, 129, 40, +/* 3020 */ 4, 50, 4, 87, 5, 129, 41, 4, 50, 4, +/* 3030 */ 86, 5, 129, 42, 4, 50, 4, 85, 5, 129, +/* 3040 */ 43, 3, 50, 4, 83, 6, 129, 44, 2, 51, +/* 3050 */ 5, 80, 7, 129, 46, 1, 52, 6, 76, 9, +/* 3060 */ 129, 54, 28, 129, 56, 23, 129, 60, 16, 129, +/* 3070 */ 193, 129, 30, 4, 132, 30, 5, 129, 30, 8, +/* 3080 */ 129, 30, 12, 129, 30, 16, 129, 30, 4, 37, +/* 3090 */ 12, 129, 30, 4, 41, 12, 129, 30, 4, 44, +/* 3100 */ 13, 129, 30, 4, 48, 13, 129, 52, 13, 129, +/* 3110 */ 56, 12, 129, 58, 14, 129, 58, 4, 64, 12, +/* 3120 */ 129, 58, 4, 68, 12, 129, 58, 4, 72, 12, +/* 3130 */ 129, 58, 4, 75, 13, 129, 58, 4, 79, 13, +/* 3140 */ 129, 58, 4, 83, 13, 129, 58, 4, 87, 13, +/* 3150 */ 129, 58, 4, 91, 12, 129, 58, 4, 95, 12, +/* 3160 */ 129, 58, 4, 96, 15, 129, 58, 4, 93, 22, +/* 3170 */ 129, 58, 4, 89, 30, 129, 58, 4, 85, 36, +/* 3180 */ 129, 58, 4, 81, 38, 129, 58, 4, 77, 38, +/* 3190 */ 129, 58, 4, 73, 38, 129, 58, 4, 70, 37, +/* 3200 */ 129, 58, 4, 66, 37, 129, 58, 41, 129, 58, +/* 3210 */ 37, 129, 54, 38, 129, 30, 4, 50, 38, 129, +/* 3220 */ 30, 4, 46, 38, 129, 30, 4, 42, 38, 129, +/* 3230 */ 30, 4, 38, 39, 129, 30, 43, 129, 30, 39, +/* 3240 */ 129, 30, 35, 129, 30, 31, 129, 30, 27, 129, +/* 3250 */ 30, 24, 129, 30, 20, 129, 30, 16, 129, 30, +/* 3260 */ 12, 129, 30, 8, 129, 30, 5, 129, 30, 4, +/* 3270 */ 132, 193, 129, 30, 4, 117, 4, 132, 30, 91, +/* 3280 */ 137, 30, 4, 80, 4, 117, 4, 138, 30, 4, +/* 3290 */ 80, 5, 116, 5, 129, 30, 5, 79, 6, 116, +/* 3300 */ 5, 130, 30, 6, 78, 8, 115, 6, 129, 31, +/* 3310 */ 6, 77, 9, 115, 6, 129, 31, 7, 76, 11, +/* 3320 */ 114, 6, 129, 31, 8, 75, 14, 112, 8, 129, +/* 3330 */ 32, 8, 74, 16, 111, 9, 129, 32, 9, 73, +/* 3340 */ 19, 109, 10, 129, 33, 10, 71, 24, 106, 13, +/* 3350 */ 129, 33, 13, 68, 12, 83, 35, 129, 34, 16, +/* 3360 */ 64, 15, 84, 33, 129, 35, 43, 85, 31, 129, +/* 3370 */ 36, 41, 86, 29, 129, 37, 39, 88, 25, 129, +/* 3380 */ 38, 37, 90, 21, 129, 40, 33, 93, 15, 129, +/* 3390 */ 42, 29, 96, 9, 129, 45, 24, 129, 49, 16, +/* 3400 */ 129, 193, 129, 63, 25, 129, 57, 37, 129, 53, +/* 3410 */ 45, 129, 50, 51, 129, 47, 57, 129, 45, 61, +/* 3420 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129, +/* 3430 */ 38, 25, 92, 21, 129, 36, 21, 97, 18, 129, +/* 3440 */ 35, 18, 102, 14, 129, 34, 16, 106, 11, 129, +/* 3450 */ 33, 14, 108, 10, 129, 32, 12, 111, 8, 129, +/* 3460 */ 32, 10, 113, 6, 129, 31, 10, 114, 6, 129, +/* 3470 */ 31, 8, 115, 5, 129, 30, 8, 116, 5, 129, +/* 3480 */ 30, 7, 116, 5, 129, 30, 6, 117, 4, 130, +/* 3490 */ 30, 5, 117, 4, 131, 31, 4, 116, 5, 129, +/* 3500 */ 32, 4, 116, 4, 129, 32, 5, 115, 5, 129, +/* 3510 */ 33, 4, 114, 5, 129, 34, 4, 112, 6, 129, +/* 3520 */ 35, 4, 110, 7, 129, 37, 4, 107, 9, 129, +/* 3530 */ 39, 4, 103, 12, 129, 41, 4, 103, 18, 129, +/* 3540 */ 43, 4, 103, 18, 129, 45, 5, 103, 18, 129, +/* 3550 */ 48, 5, 103, 18, 129, 51, 1, 129, 193, 129, +/* 3560 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4, +/* 3570 */ 117, 4, 135, 30, 5, 116, 5, 130, 30, 6, +/* 3580 */ 115, 6, 130, 31, 6, 114, 6, 129, 31, 7, +/* 3590 */ 113, 7, 129, 32, 7, 112, 7, 129, 32, 8, +/* 3600 */ 111, 8, 129, 33, 9, 109, 9, 129, 33, 12, +/* 3610 */ 106, 12, 129, 34, 13, 104, 13, 129, 35, 15, +/* 3620 */ 101, 15, 129, 36, 19, 96, 19, 129, 37, 24, +/* 3630 */ 90, 24, 129, 39, 73, 129, 40, 71, 129, 42, +/* 3640 */ 67, 129, 44, 63, 129, 46, 59, 129, 49, 53, +/* 3650 */ 129, 52, 47, 129, 56, 39, 129, 61, 29, 129, +/* 3660 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 137, +/* 3670 */ 30, 4, 80, 4, 117, 4, 140, 30, 4, 79, +/* 3680 */ 6, 117, 4, 129, 30, 4, 77, 10, 117, 4, +/* 3690 */ 129, 30, 4, 73, 18, 117, 4, 132, 30, 4, +/* 3700 */ 117, 4, 130, 30, 5, 116, 5, 130, 30, 7, +/* 3710 */ 114, 7, 129, 30, 8, 113, 8, 129, 30, 11, +/* 3720 */ 110, 11, 129, 30, 18, 103, 18, 132, 193, 129, +/* 3730 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4, +/* 3740 */ 80, 4, 117, 4, 132, 80, 4, 117, 4, 136, +/* 3750 */ 79, 6, 117, 4, 129, 77, 10, 117, 4, 129, +/* 3760 */ 73, 18, 117, 4, 132, 117, 4, 130, 116, 5, +/* 3770 */ 130, 114, 7, 129, 113, 8, 129, 110, 11, 129, +/* 3780 */ 103, 18, 132, 193, 129, 63, 25, 129, 57, 37, +/* 3790 */ 129, 53, 45, 129, 50, 51, 129, 47, 57, 129, +/* 3800 */ 45, 61, 129, 43, 65, 129, 41, 69, 129, 39, +/* 3810 */ 73, 129, 38, 25, 92, 21, 129, 36, 21, 97, +/* 3820 */ 18, 129, 35, 18, 102, 14, 129, 34, 16, 106, +/* 3830 */ 11, 129, 33, 14, 108, 10, 129, 32, 12, 111, +/* 3840 */ 8, 129, 32, 10, 113, 6, 129, 31, 10, 114, +/* 3850 */ 6, 129, 31, 8, 115, 5, 129, 30, 8, 116, +/* 3860 */ 5, 129, 30, 7, 116, 5, 129, 30, 6, 117, +/* 3870 */ 4, 130, 30, 5, 117, 4, 131, 30, 5, 75, +/* 3880 */ 4, 116, 5, 129, 31, 5, 75, 4, 116, 4, +/* 3890 */ 129, 31, 6, 75, 4, 115, 5, 129, 32, 7, +/* 3900 */ 75, 4, 114, 5, 129, 32, 9, 75, 4, 112, +/* 3910 */ 6, 129, 33, 11, 75, 4, 110, 7, 129, 34, +/* 3920 */ 15, 75, 4, 107, 9, 129, 35, 44, 103, 12, +/* 3930 */ 129, 36, 43, 103, 18, 129, 38, 41, 103, 18, +/* 3940 */ 129, 39, 40, 103, 18, 129, 41, 38, 103, 18, +/* 3950 */ 129, 44, 35, 129, 48, 31, 129, 52, 27, 129, +/* 3960 */ 61, 18, 129, 193, 129, 30, 4, 117, 4, 132, +/* 3970 */ 30, 91, 137, 30, 4, 80, 4, 117, 4, 132, +/* 3980 */ 80, 4, 140, 30, 4, 80, 4, 117, 4, 132, +/* 3990 */ 30, 91, 137, 30, 4, 117, 4, 132, 193, 129, +/* 4000 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4, +/* 4010 */ 117, 4, 132, 193, 129, 44, 7, 129, 40, 13, +/* 4020 */ 129, 37, 17, 129, 35, 20, 129, 34, 22, 129, +/* 4030 */ 33, 23, 129, 32, 24, 129, 32, 23, 129, 31, +/* 4040 */ 6, 41, 13, 129, 31, 5, 42, 11, 129, 30, +/* 4050 */ 5, 44, 7, 129, 30, 4, 132, 30, 5, 130, +/* 4060 */ 31, 5, 129, 31, 6, 117, 4, 129, 31, 8, +/* 4070 */ 117, 4, 129, 32, 9, 117, 4, 129, 33, 11, +/* 4080 */ 117, 4, 129, 34, 87, 129, 35, 86, 129, 36, +/* 4090 */ 85, 129, 37, 84, 129, 38, 83, 129, 40, 81, +/* 4100 */ 129, 42, 79, 129, 45, 76, 129, 50, 71, 129, +/* 4110 */ 117, 4, 132, 193, 129, 30, 4, 117, 4, 132, +/* 4120 */ 30, 91, 137, 30, 4, 76, 8, 117, 4, 129, +/* 4130 */ 30, 4, 73, 13, 117, 4, 129, 30, 4, 70, +/* 4140 */ 18, 117, 4, 129, 30, 4, 67, 23, 117, 4, +/* 4150 */ 129, 65, 26, 129, 62, 31, 129, 59, 35, 129, +/* 4160 */ 56, 29, 89, 7, 129, 53, 29, 91, 7, 129, +/* 4170 */ 50, 29, 93, 7, 129, 47, 29, 95, 6, 129, +/* 4180 */ 30, 4, 45, 29, 96, 7, 129, 30, 4, 42, +/* 4190 */ 29, 98, 7, 129, 30, 4, 39, 30, 100, 6, +/* 4200 */ 129, 30, 4, 36, 30, 101, 7, 129, 30, 33, +/* 4210 */ 103, 7, 117, 4, 129, 30, 30, 105, 6, 117, +/* 4220 */ 4, 129, 30, 27, 106, 7, 117, 4, 129, 30, +/* 4230 */ 25, 108, 7, 117, 4, 129, 30, 22, 110, 11, +/* 4240 */ 129, 30, 19, 111, 10, 129, 30, 16, 113, 8, +/* 4250 */ 129, 30, 13, 115, 6, 129, 30, 11, 116, 5, +/* 4260 */ 129, 30, 8, 117, 4, 129, 30, 5, 117, 4, +/* 4270 */ 129, 30, 4, 117, 4, 130, 30, 4, 130, 193, +/* 4280 */ 129, 30, 4, 117, 4, 132, 30, 91, 137, 30, +/* 4290 */ 4, 117, 4, 132, 30, 4, 144, 30, 5, 130, +/* 4300 */ 30, 7, 129, 30, 8, 129, 30, 11, 129, 30, +/* 4310 */ 18, 132, 193, 129, 30, 4, 117, 4, 132, 30, +/* 4320 */ 91, 132, 30, 4, 103, 18, 129, 30, 4, 97, +/* 4330 */ 24, 129, 30, 4, 92, 29, 129, 30, 4, 87, +/* 4340 */ 34, 129, 81, 40, 129, 76, 45, 129, 70, 49, +/* 4350 */ 129, 65, 49, 129, 60, 49, 129, 55, 49, 129, +/* 4360 */ 50, 48, 129, 44, 49, 129, 39, 48, 129, 33, +/* 4370 */ 49, 129, 30, 47, 129, 34, 37, 129, 40, 26, +/* 4380 */ 129, 46, 19, 129, 52, 19, 129, 58, 19, 129, +/* 4390 */ 64, 19, 129, 70, 19, 129, 76, 19, 129, 82, +/* 4400 */ 19, 129, 30, 4, 88, 18, 129, 30, 4, 94, +/* 4410 */ 18, 129, 30, 4, 100, 18, 129, 30, 4, 106, +/* 4420 */ 15, 129, 30, 91, 137, 30, 4, 117, 4, 132, +/* 4430 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 132, +/* 4440 */ 30, 4, 107, 14, 129, 30, 4, 104, 17, 129, +/* 4450 */ 30, 4, 101, 20, 129, 30, 4, 99, 22, 129, +/* 4460 */ 96, 25, 129, 93, 28, 129, 91, 28, 129, 88, +/* 4470 */ 29, 129, 85, 29, 129, 82, 29, 129, 79, 29, +/* 4480 */ 129, 76, 29, 129, 74, 29, 129, 71, 29, 129, +/* 4490 */ 68, 29, 129, 65, 29, 129, 62, 29, 129, 60, +/* 4500 */ 29, 129, 57, 29, 129, 54, 29, 129, 51, 29, +/* 4510 */ 129, 49, 28, 129, 46, 29, 129, 43, 29, 129, +/* 4520 */ 40, 29, 117, 4, 129, 37, 29, 117, 4, 129, +/* 4530 */ 35, 29, 117, 4, 129, 32, 29, 117, 4, 129, +/* 4540 */ 30, 91, 132, 117, 4, 132, 193, 129, 63, 25, +/* 4550 */ 129, 57, 37, 129, 53, 45, 129, 50, 51, 129, +/* 4560 */ 47, 57, 129, 45, 61, 129, 43, 65, 129, 41, +/* 4570 */ 69, 129, 39, 73, 129, 38, 21, 92, 21, 129, +/* 4580 */ 36, 18, 97, 18, 129, 35, 14, 102, 14, 129, +/* 4590 */ 34, 11, 106, 11, 129, 33, 10, 108, 10, 129, +/* 4600 */ 32, 8, 111, 8, 129, 32, 6, 113, 6, 129, +/* 4610 */ 31, 6, 114, 6, 129, 31, 5, 115, 5, 129, +/* 4620 */ 30, 5, 116, 5, 130, 30, 4, 117, 4, 132, +/* 4630 */ 30, 5, 116, 5, 130, 31, 5, 115, 5, 129, +/* 4640 */ 31, 6, 114, 6, 129, 32, 6, 113, 6, 129, +/* 4650 */ 32, 8, 111, 8, 129, 33, 10, 108, 10, 129, +/* 4660 */ 34, 11, 106, 11, 129, 35, 14, 102, 14, 129, +/* 4670 */ 36, 18, 97, 18, 129, 38, 21, 92, 21, 129, +/* 4680 */ 39, 73, 129, 41, 69, 129, 43, 65, 129, 45, +/* 4690 */ 61, 129, 47, 57, 129, 50, 51, 129, 53, 45, +/* 4700 */ 129, 57, 37, 129, 63, 25, 129, 193, 129, 30, +/* 4710 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 80, +/* 4720 */ 4, 117, 4, 132, 80, 4, 117, 4, 134, 80, +/* 4730 */ 5, 116, 5, 131, 80, 6, 115, 6, 130, 81, +/* 4740 */ 6, 114, 6, 129, 81, 8, 112, 8, 129, 81, +/* 4750 */ 9, 111, 9, 129, 82, 10, 109, 10, 129, 82, +/* 4760 */ 13, 106, 13, 129, 83, 35, 129, 84, 33, 129, +/* 4770 */ 85, 31, 129, 86, 29, 129, 88, 25, 129, 90, +/* 4780 */ 21, 129, 93, 15, 129, 96, 9, 129, 193, 129, +/* 4790 */ 63, 25, 129, 57, 37, 129, 53, 45, 129, 50, +/* 4800 */ 51, 129, 47, 57, 129, 45, 61, 129, 43, 65, +/* 4810 */ 129, 41, 69, 129, 39, 73, 129, 38, 21, 92, +/* 4820 */ 21, 129, 36, 18, 97, 18, 129, 35, 14, 102, +/* 4830 */ 14, 129, 34, 11, 106, 11, 129, 33, 10, 108, +/* 4840 */ 10, 129, 32, 8, 111, 8, 129, 32, 6, 113, +/* 4850 */ 6, 129, 31, 6, 114, 6, 129, 31, 5, 115, +/* 4860 */ 5, 129, 30, 5, 116, 5, 130, 30, 4, 39, +/* 4870 */ 2, 117, 4, 129, 30, 4, 40, 4, 117, 4, +/* 4880 */ 129, 30, 4, 41, 5, 117, 4, 129, 30, 4, +/* 4890 */ 41, 6, 117, 4, 129, 30, 5, 40, 8, 116, +/* 4900 */ 5, 129, 30, 5, 39, 10, 116, 5, 129, 31, +/* 4910 */ 5, 38, 11, 115, 5, 129, 31, 18, 114, 6, +/* 4920 */ 129, 32, 17, 113, 6, 129, 32, 16, 111, 8, +/* 4930 */ 129, 33, 15, 108, 10, 129, 33, 14, 106, 11, +/* 4940 */ 129, 32, 17, 102, 14, 129, 31, 23, 97, 18, +/* 4950 */ 129, 31, 28, 92, 21, 129, 30, 82, 129, 30, +/* 4960 */ 80, 129, 30, 11, 43, 65, 129, 30, 10, 45, +/* 4970 */ 61, 129, 31, 8, 47, 57, 129, 32, 6, 50, +/* 4980 */ 51, 129, 33, 5, 53, 45, 129, 35, 4, 57, +/* 4990 */ 37, 129, 38, 2, 63, 25, 129, 193, 129, 30, +/* 5000 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 76, +/* 5010 */ 8, 117, 4, 129, 30, 4, 73, 11, 117, 4, +/* 5020 */ 129, 30, 4, 70, 14, 117, 4, 129, 30, 4, +/* 5030 */ 67, 17, 117, 4, 129, 65, 19, 117, 4, 129, +/* 5040 */ 62, 22, 117, 4, 129, 59, 25, 117, 4, 129, +/* 5050 */ 56, 28, 117, 4, 129, 53, 31, 117, 4, 129, +/* 5060 */ 50, 34, 117, 4, 129, 47, 29, 80, 5, 116, +/* 5070 */ 5, 129, 30, 4, 45, 29, 80, 5, 116, 5, +/* 5080 */ 129, 30, 4, 42, 29, 80, 5, 116, 5, 129, +/* 5090 */ 30, 4, 39, 30, 80, 6, 115, 6, 129, 30, +/* 5100 */ 4, 36, 30, 80, 6, 115, 6, 129, 30, 33, +/* 5110 */ 81, 6, 114, 6, 129, 30, 30, 81, 8, 112, +/* 5120 */ 8, 129, 30, 27, 81, 9, 111, 9, 129, 30, +/* 5130 */ 25, 82, 10, 109, 10, 129, 30, 22, 82, 13, +/* 5140 */ 106, 13, 129, 30, 19, 83, 35, 129, 30, 16, +/* 5150 */ 84, 33, 129, 30, 13, 85, 31, 129, 30, 11, +/* 5160 */ 86, 29, 129, 30, 8, 88, 25, 129, 30, 5, +/* 5170 */ 90, 21, 129, 30, 4, 93, 15, 129, 30, 4, +/* 5180 */ 96, 9, 129, 30, 4, 130, 193, 129, 30, 18, +/* 5190 */ 130, 30, 18, 89, 15, 129, 30, 18, 85, 23, +/* 5200 */ 129, 34, 11, 83, 27, 129, 34, 9, 81, 31, +/* 5210 */ 129, 33, 8, 79, 35, 129, 33, 6, 78, 16, +/* 5220 */ 106, 9, 129, 32, 6, 77, 15, 109, 7, 129, +/* 5230 */ 32, 5, 76, 14, 111, 6, 129, 31, 5, 75, +/* 5240 */ 14, 113, 5, 129, 31, 4, 74, 15, 114, 5, +/* 5250 */ 129, 31, 4, 74, 14, 115, 4, 129, 30, 4, +/* 5260 */ 73, 15, 116, 4, 129, 30, 4, 73, 14, 116, +/* 5270 */ 4, 129, 30, 4, 73, 14, 117, 4, 129, 30, +/* 5280 */ 4, 72, 15, 117, 4, 130, 30, 4, 71, 15, +/* 5290 */ 117, 4, 130, 30, 4, 70, 15, 117, 4, 129, +/* 5300 */ 30, 5, 70, 15, 117, 4, 129, 30, 5, 69, +/* 5310 */ 15, 116, 5, 129, 30, 6, 68, 16, 115, 5, +/* 5320 */ 129, 31, 6, 67, 16, 114, 6, 129, 31, 7, +/* 5330 */ 66, 17, 113, 6, 129, 32, 7, 64, 18, 111, +/* 5340 */ 8, 129, 32, 8, 62, 19, 109, 9, 129, 33, +/* 5350 */ 9, 60, 20, 107, 10, 129, 34, 11, 57, 22, +/* 5360 */ 103, 13, 129, 35, 43, 103, 18, 129, 36, 41, +/* 5370 */ 103, 18, 129, 38, 38, 103, 18, 129, 39, 35, +/* 5380 */ 103, 18, 129, 41, 31, 129, 43, 27, 129, 46, +/* 5390 */ 22, 129, 49, 14, 129, 193, 129, 103, 18, 132, +/* 5400 */ 110, 11, 129, 113, 8, 129, 114, 7, 129, 116, +/* 5410 */ 5, 130, 117, 4, 132, 30, 4, 117, 4, 132, +/* 5420 */ 30, 91, 137, 30, 4, 117, 4, 132, 117, 4, +/* 5430 */ 132, 116, 5, 130, 114, 7, 129, 113, 8, 129, +/* 5440 */ 110, 11, 129, 103, 18, 132, 193, 129, 117, 4, +/* 5450 */ 132, 56, 65, 129, 50, 71, 129, 46, 75, 129, +/* 5460 */ 44, 77, 129, 42, 79, 129, 40, 81, 129, 38, +/* 5470 */ 83, 129, 36, 85, 129, 35, 86, 129, 34, 20, +/* 5480 */ 117, 4, 129, 33, 17, 117, 4, 129, 32, 15, +/* 5490 */ 117, 4, 129, 32, 13, 117, 4, 129, 31, 12, +/* 5500 */ 129, 31, 10, 129, 31, 9, 129, 30, 9, 129, +/* 5510 */ 30, 8, 130, 30, 7, 132, 31, 6, 130, 31, +/* 5520 */ 7, 129, 32, 6, 129, 32, 7, 129, 33, 7, +/* 5530 */ 129, 34, 7, 129, 35, 8, 129, 36, 9, 117, +/* 5540 */ 4, 129, 38, 9, 117, 4, 129, 40, 10, 117, +/* 5550 */ 4, 129, 42, 12, 117, 4, 129, 44, 77, 129, +/* 5560 */ 46, 75, 129, 50, 71, 129, 56, 43, 100, 21, +/* 5570 */ 129, 117, 4, 132, 193, 129, 117, 4, 132, 115, +/* 5580 */ 6, 129, 110, 11, 129, 105, 16, 129, 101, 20, +/* 5590 */ 129, 96, 25, 129, 92, 29, 129, 87, 34, 129, +/* 5600 */ 83, 38, 129, 78, 43, 129, 74, 47, 129, 70, +/* 5610 */ 42, 117, 4, 129, 65, 42, 117, 4, 129, 60, +/* 5620 */ 43, 117, 4, 129, 56, 42, 129, 51, 42, 129, +/* 5630 */ 46, 43, 129, 42, 43, 129, 37, 44, 129, 33, +/* 5640 */ 43, 129, 30, 42, 129, 33, 34, 129, 38, 25, +/* 5650 */ 129, 42, 16, 129, 47, 15, 129, 52, 15, 129, +/* 5660 */ 57, 15, 129, 61, 16, 129, 66, 16, 129, 71, +/* 5670 */ 16, 129, 76, 16, 129, 80, 16, 129, 85, 16, +/* 5680 */ 117, 4, 129, 90, 16, 117, 4, 129, 95, 16, +/* 5690 */ 117, 4, 129, 100, 21, 129, 105, 16, 129, 110, +/* 5700 */ 11, 129, 114, 7, 129, 117, 4, 132, 193, 129, +/* 5710 */ 117, 4, 132, 115, 6, 129, 110, 11, 129, 105, +/* 5720 */ 16, 129, 101, 20, 129, 96, 25, 129, 92, 29, +/* 5730 */ 129, 87, 34, 129, 83, 38, 129, 78, 43, 129, +/* 5740 */ 74, 47, 129, 70, 42, 117, 4, 129, 65, 42, +/* 5750 */ 117, 4, 129, 60, 43, 117, 4, 129, 56, 42, +/* 5760 */ 129, 51, 42, 129, 46, 43, 129, 42, 43, 129, +/* 5770 */ 37, 44, 129, 33, 43, 129, 30, 42, 129, 33, +/* 5780 */ 34, 129, 38, 25, 129, 42, 16, 129, 47, 15, +/* 5790 */ 129, 52, 15, 129, 57, 15, 129, 61, 16, 129, +/* 5800 */ 65, 17, 129, 60, 27, 129, 56, 36, 129, 51, +/* 5810 */ 42, 129, 46, 43, 129, 42, 43, 129, 37, 44, +/* 5820 */ 129, 33, 43, 129, 30, 42, 129, 33, 34, 129, +/* 5830 */ 38, 25, 129, 42, 16, 129, 47, 15, 129, 52, +/* 5840 */ 15, 129, 57, 15, 129, 61, 16, 129, 66, 16, +/* 5850 */ 129, 71, 16, 129, 76, 16, 129, 80, 16, 129, +/* 5860 */ 85, 16, 117, 4, 129, 90, 16, 117, 4, 129, +/* 5870 */ 95, 16, 117, 4, 129, 100, 21, 129, 105, 16, +/* 5880 */ 129, 110, 11, 129, 114, 7, 129, 117, 4, 132, +/* 5890 */ 193, 129, 30, 4, 117, 4, 132, 30, 4, 115, +/* 5900 */ 6, 129, 30, 4, 112, 9, 129, 30, 6, 109, +/* 5910 */ 12, 129, 30, 9, 106, 15, 129, 30, 11, 103, +/* 5920 */ 18, 129, 30, 14, 100, 21, 129, 30, 4, 38, +/* 5930 */ 9, 98, 23, 129, 30, 4, 40, 10, 95, 26, +/* 5940 */ 129, 30, 4, 43, 9, 92, 29, 129, 46, 9, +/* 5950 */ 89, 32, 129, 49, 8, 86, 28, 117, 4, 129, +/* 5960 */ 51, 9, 83, 28, 117, 4, 129, 54, 9, 80, +/* 5970 */ 28, 117, 4, 129, 57, 8, 77, 28, 117, 4, +/* 5980 */ 129, 59, 9, 74, 28, 129, 62, 37, 129, 64, +/* 5990 */ 33, 129, 66, 28, 129, 63, 28, 129, 60, 28, +/* 6000 */ 129, 57, 28, 129, 54, 33, 129, 51, 39, 129, +/* 6010 */ 48, 29, 83, 9, 129, 30, 4, 45, 29, 86, +/* 6020 */ 9, 129, 30, 4, 42, 29, 89, 9, 129, 30, +/* 6030 */ 4, 39, 29, 92, 8, 129, 30, 4, 36, 29, +/* 6040 */ 94, 9, 129, 30, 32, 97, 9, 129, 30, 29, +/* 6050 */ 100, 8, 117, 4, 129, 30, 26, 103, 8, 117, +/* 6060 */ 4, 129, 30, 23, 105, 9, 117, 4, 129, 30, +/* 6070 */ 20, 108, 13, 129, 30, 18, 111, 10, 129, 30, +/* 6080 */ 15, 113, 8, 129, 30, 12, 116, 5, 129, 30, +/* 6090 */ 9, 117, 4, 129, 30, 6, 117, 4, 129, 30, +/* 6100 */ 4, 117, 4, 132, 193, 129, 117, 4, 132, 114, +/* 6110 */ 7, 129, 111, 10, 129, 108, 13, 129, 105, 16, +/* 6120 */ 129, 102, 19, 129, 100, 21, 129, 96, 25, 129, +/* 6130 */ 93, 28, 129, 90, 31, 129, 87, 34, 129, 84, +/* 6140 */ 30, 117, 4, 129, 30, 4, 81, 30, 117, 4, +/* 6150 */ 129, 30, 4, 78, 30, 117, 4, 129, 30, 4, +/* 6160 */ 75, 30, 117, 4, 129, 30, 4, 72, 30, 129, +/* 6170 */ 30, 69, 129, 30, 66, 129, 30, 63, 129, 30, +/* 6180 */ 60, 129, 30, 57, 129, 30, 54, 129, 30, 51, +/* 6190 */ 129, 30, 48, 129, 30, 51, 129, 30, 4, 73, +/* 6200 */ 12, 129, 30, 4, 76, 12, 129, 30, 4, 80, +/* 6210 */ 12, 129, 30, 4, 83, 12, 129, 87, 12, 129, +/* 6220 */ 90, 12, 117, 4, 129, 94, 11, 117, 4, 129, +/* 6230 */ 97, 12, 117, 4, 129, 101, 12, 117, 4, 129, +/* 6240 */ 104, 17, 129, 108, 13, 129, 111, 10, 129, 115, +/* 6250 */ 6, 129, 117, 4, 134, 193, 129, 30, 1, 103, +/* 6260 */ 18, 129, 30, 4, 103, 18, 129, 30, 7, 103, +/* 6270 */ 18, 129, 30, 9, 103, 18, 129, 30, 12, 110, +/* 6280 */ 11, 129, 30, 15, 113, 8, 129, 30, 18, 114, +/* 6290 */ 7, 129, 30, 21, 116, 5, 129, 30, 24, 116, +/* 6300 */ 5, 129, 30, 27, 117, 4, 129, 30, 30, 117, +/* 6310 */ 4, 129, 30, 33, 117, 4, 129, 30, 4, 37, +/* 6320 */ 28, 117, 4, 129, 30, 4, 40, 28, 117, 4, +/* 6330 */ 129, 30, 4, 42, 29, 117, 4, 129, 30, 4, +/* 6340 */ 45, 29, 117, 4, 129, 30, 4, 48, 29, 117, +/* 6350 */ 4, 129, 30, 4, 51, 29, 117, 4, 129, 30, +/* 6360 */ 4, 54, 29, 117, 4, 129, 30, 4, 57, 29, +/* 6370 */ 117, 4, 129, 30, 4, 59, 30, 117, 4, 129, +/* 6380 */ 30, 4, 62, 30, 117, 4, 129, 30, 4, 65, +/* 6390 */ 30, 117, 4, 129, 30, 4, 68, 30, 117, 4, +/* 6400 */ 129, 30, 4, 71, 30, 117, 4, 129, 30, 4, +/* 6410 */ 74, 30, 117, 4, 129, 30, 4, 77, 30, 117, +/* 6420 */ 4, 129, 30, 4, 80, 30, 117, 4, 129, 30, +/* 6430 */ 4, 83, 30, 117, 4, 129, 30, 4, 86, 35, +/* 6440 */ 129, 30, 4, 89, 32, 129, 30, 4, 91, 30, +/* 6450 */ 129, 30, 4, 94, 27, 129, 30, 5, 97, 24, +/* 6460 */ 129, 30, 5, 100, 21, 129, 30, 7, 103, 18, +/* 6470 */ 129, 30, 8, 106, 15, 129, 30, 11, 109, 12, +/* 6480 */ 129, 30, 18, 112, 9, 129, 30, 18, 115, 6, +/* 6490 */ 129, 30, 18, 117, 4, 129, 30, 18, 120, 1, +/* 6500 */ 129, 193, 129, 42, 8, 129, 38, 16, 129, 36, +/* 6510 */ 20, 129, 34, 24, 71, 5, 129, 33, 26, 69, +/* 6520 */ 10, 129, 32, 28, 68, 13, 129, 31, 30, 68, +/* 6530 */ 14, 129, 31, 9, 52, 9, 68, 15, 129, 30, +/* 6540 */ 8, 54, 8, 69, 14, 129, 30, 7, 55, 7, +/* 6550 */ 71, 4, 78, 6, 129, 30, 6, 56, 6, 79, +/* 6560 */ 5, 129, 30, 6, 56, 6, 80, 4, 130, 31, +/* 6570 */ 5, 56, 5, 80, 4, 129, 31, 5, 56, 5, +/* 6580 */ 79, 5, 129, 32, 5, 55, 5, 78, 6, 129, +/* 6590 */ 33, 5, 54, 5, 77, 7, 129, 34, 6, 52, +/* 6600 */ 6, 74, 9, 129, 35, 48, 129, 33, 49, 129, +/* 6610 */ 32, 49, 129, 31, 49, 129, 30, 49, 129, 30, +/* 6620 */ 47, 129, 30, 45, 129, 30, 41, 129, 30, 6, +/* 6630 */ 129, 30, 4, 129, 30, 3, 129, 30, 2, 129, +/* 6640 */ 193, 129, 30, 4, 117, 4, 130, 31, 90, 136, +/* 6650 */ 37, 5, 72, 5, 129, 35, 5, 74, 5, 129, +/* 6660 */ 33, 5, 76, 5, 129, 32, 5, 77, 5, 129, +/* 6670 */ 31, 5, 78, 5, 129, 31, 4, 79, 4, 129, +/* 6680 */ 30, 5, 79, 5, 131, 30, 6, 78, 6, 129, +/* 6690 */ 30, 7, 77, 7, 129, 31, 8, 75, 8, 129, +/* 6700 */ 31, 11, 72, 11, 129, 32, 15, 67, 15, 129, +/* 6710 */ 33, 48, 129, 34, 46, 129, 35, 44, 129, 37, +/* 6720 */ 40, 129, 39, 36, 129, 42, 30, 129, 46, 22, +/* 6730 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41, +/* 6740 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44, +/* 6750 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32, +/* 6760 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31, +/* 6770 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30, +/* 6780 */ 5, 79, 5, 129, 30, 4, 80, 4, 133, 31, +/* 6790 */ 3, 79, 4, 129, 31, 4, 79, 4, 129, 32, +/* 6800 */ 3, 78, 4, 129, 32, 4, 76, 6, 129, 33, +/* 6810 */ 4, 74, 7, 129, 34, 4, 72, 8, 129, 35, +/* 6820 */ 5, 72, 7, 129, 37, 5, 73, 4, 129, 39, +/* 6830 */ 4, 74, 1, 129, 129, 193, 129, 46, 22, 129, +/* 6840 */ 42, 30, 129, 39, 36, 129, 37, 40, 129, 35, +/* 6850 */ 44, 129, 34, 46, 129, 33, 48, 129, 32, 15, +/* 6860 */ 67, 15, 129, 31, 11, 72, 11, 129, 31, 8, +/* 6870 */ 75, 8, 129, 30, 7, 77, 7, 129, 30, 6, +/* 6880 */ 78, 6, 129, 30, 5, 79, 5, 131, 31, 4, +/* 6890 */ 79, 4, 129, 31, 5, 78, 5, 129, 32, 5, +/* 6900 */ 77, 5, 129, 33, 5, 76, 5, 129, 35, 5, +/* 6910 */ 74, 5, 117, 4, 129, 37, 5, 72, 5, 117, +/* 6920 */ 4, 129, 30, 91, 136, 30, 4, 130, 193, 129, +/* 6930 */ 48, 18, 129, 43, 28, 129, 41, 32, 129, 39, +/* 6940 */ 36, 129, 37, 40, 129, 35, 44, 129, 34, 46, +/* 6950 */ 129, 33, 13, 55, 4, 68, 13, 129, 32, 9, +/* 6960 */ 55, 4, 73, 9, 129, 32, 7, 55, 4, 75, +/* 6970 */ 7, 129, 31, 6, 55, 4, 77, 6, 129, 31, +/* 6980 */ 5, 55, 4, 78, 5, 129, 30, 5, 55, 4, +/* 6990 */ 79, 5, 129, 30, 4, 55, 4, 80, 4, 132, +/* 7000 */ 30, 4, 55, 4, 79, 5, 129, 31, 3, 55, +/* 7010 */ 4, 78, 5, 129, 31, 4, 55, 4, 77, 6, +/* 7020 */ 129, 32, 3, 55, 4, 75, 7, 129, 32, 4, +/* 7030 */ 55, 4, 73, 9, 129, 33, 4, 55, 4, 68, +/* 7040 */ 13, 129, 34, 4, 55, 25, 129, 35, 5, 55, +/* 7050 */ 24, 129, 37, 5, 55, 22, 129, 39, 4, 55, +/* 7060 */ 20, 129, 55, 18, 129, 55, 16, 129, 55, 11, +/* 7070 */ 129, 193, 129, 80, 4, 129, 30, 4, 80, 4, +/* 7080 */ 130, 30, 78, 129, 30, 82, 129, 30, 85, 129, +/* 7090 */ 30, 87, 129, 30, 88, 129, 30, 89, 129, 30, +/* 7100 */ 90, 130, 30, 4, 80, 4, 115, 6, 129, 30, +/* 7110 */ 4, 80, 4, 117, 4, 129, 80, 4, 105, 6, +/* 7120 */ 117, 4, 129, 80, 4, 103, 10, 116, 5, 129, +/* 7130 */ 80, 4, 102, 19, 129, 80, 4, 101, 19, 129, +/* 7140 */ 101, 19, 129, 101, 18, 129, 102, 16, 129, 103, +/* 7150 */ 12, 129, 105, 6, 129, 193, 129, 12, 10, 59, +/* 7160 */ 11, 129, 9, 16, 55, 19, 129, 7, 20, 53, +/* 7170 */ 23, 129, 6, 7, 23, 5, 32, 6, 51, 27, +/* 7180 */ 129, 4, 7, 25, 16, 50, 29, 129, 3, 6, +/* 7190 */ 27, 16, 49, 31, 129, 2, 6, 28, 16, 48, +/* 7200 */ 33, 129, 1, 6, 27, 18, 47, 35, 129, 1, +/* 7210 */ 6, 27, 31, 71, 12, 129, 1, 5, 26, 15, +/* 7220 */ 44, 10, 75, 8, 129, 1, 5, 25, 14, 45, +/* 7230 */ 7, 77, 7, 129, 1, 5, 25, 13, 45, 5, +/* 7240 */ 79, 5, 129, 1, 5, 24, 14, 45, 4, 80, +/* 7250 */ 4, 129, 1, 5, 24, 13, 45, 4, 80, 4, +/* 7260 */ 129, 1, 5, 23, 14, 45, 4, 80, 4, 129, +/* 7270 */ 1, 5, 23, 13, 45, 4, 80, 4, 129, 1, +/* 7280 */ 6, 22, 13, 45, 5, 79, 5, 129, 1, 6, +/* 7290 */ 21, 14, 45, 7, 77, 7, 129, 1, 7, 21, +/* 7300 */ 13, 46, 8, 75, 8, 129, 1, 8, 20, 13, +/* 7310 */ 46, 12, 71, 12, 129, 1, 10, 18, 15, 47, +/* 7320 */ 35, 129, 2, 30, 48, 33, 129, 3, 29, 49, +/* 7330 */ 32, 129, 4, 27, 50, 31, 129, 5, 25, 51, +/* 7340 */ 27, 80, 2, 86, 4, 129, 7, 21, 53, 23, +/* 7350 */ 80, 3, 85, 6, 129, 9, 17, 55, 19, 80, +/* 7360 */ 12, 129, 12, 12, 59, 11, 81, 11, 129, 82, +/* 7370 */ 10, 129, 84, 7, 129, 86, 4, 129, 193, 129, +/* 7380 */ 30, 4, 117, 4, 130, 30, 91, 136, 30, 4, +/* 7390 */ 72, 5, 129, 30, 4, 74, 5, 129, 75, 5, +/* 7400 */ 129, 76, 5, 129, 76, 6, 129, 77, 6, 130, +/* 7410 */ 77, 7, 130, 76, 8, 129, 30, 4, 75, 9, +/* 7420 */ 129, 30, 4, 72, 12, 129, 30, 54, 129, 30, +/* 7430 */ 53, 130, 30, 52, 129, 30, 51, 129, 30, 49, +/* 7440 */ 129, 30, 46, 129, 30, 42, 129, 30, 4, 130, +/* 7450 */ 193, 129, 30, 4, 80, 4, 129, 30, 4, 80, +/* 7460 */ 4, 100, 6, 129, 30, 54, 98, 10, 129, 30, +/* 7470 */ 54, 97, 12, 129, 30, 54, 96, 14, 131, 30, +/* 7480 */ 54, 97, 12, 129, 30, 54, 98, 10, 129, 30, +/* 7490 */ 54, 100, 6, 129, 30, 4, 130, 193, 129, 7, +/* 7500 */ 6, 129, 4, 11, 129, 3, 13, 129, 2, 14, +/* 7510 */ 129, 1, 15, 130, 1, 3, 6, 9, 129, 1, +/* 7520 */ 3, 7, 6, 129, 1, 3, 130, 1, 4, 129, +/* 7530 */ 1, 5, 80, 4, 129, 1, 7, 80, 4, 100, +/* 7540 */ 6, 129, 2, 82, 98, 10, 129, 3, 81, 97, +/* 7550 */ 12, 129, 4, 80, 96, 14, 129, 5, 79, 96, +/* 7560 */ 14, 129, 7, 77, 96, 14, 129, 10, 74, 97, +/* 7570 */ 12, 129, 14, 70, 98, 10, 129, 19, 65, 100, +/* 7580 */ 6, 129, 193, 129, 30, 4, 117, 4, 130, 30, +/* 7590 */ 91, 136, 30, 4, 57, 9, 129, 30, 4, 55, +/* 7600 */ 12, 129, 52, 17, 129, 50, 20, 129, 48, 24, +/* 7610 */ 129, 46, 27, 129, 44, 21, 69, 6, 129, 41, +/* 7620 */ 22, 70, 6, 80, 4, 129, 30, 4, 39, 21, +/* 7630 */ 72, 6, 80, 4, 129, 30, 4, 36, 22, 73, +/* 7640 */ 11, 129, 30, 26, 75, 9, 129, 30, 23, 76, +/* 7650 */ 8, 129, 30, 21, 78, 6, 129, 30, 19, 79, +/* 7660 */ 5, 129, 30, 16, 80, 4, 129, 30, 14, 80, +/* 7670 */ 4, 129, 30, 12, 129, 30, 10, 129, 30, 7, +/* 7680 */ 129, 30, 5, 129, 30, 4, 130, 193, 129, 30, +/* 7690 */ 4, 117, 4, 130, 30, 91, 136, 30, 4, 130, +/* 7700 */ 193, 129, 30, 4, 80, 4, 130, 30, 54, 136, +/* 7710 */ 30, 4, 72, 5, 129, 30, 4, 74, 5, 129, +/* 7720 */ 75, 5, 129, 76, 5, 129, 30, 4, 75, 7, +/* 7730 */ 129, 30, 4, 74, 9, 129, 30, 54, 132, 30, +/* 7740 */ 53, 129, 30, 52, 129, 30, 51, 129, 30, 48, +/* 7750 */ 129, 30, 4, 72, 5, 129, 30, 4, 74, 5, +/* 7760 */ 129, 75, 5, 129, 76, 5, 129, 30, 4, 75, +/* 7770 */ 7, 129, 30, 4, 74, 9, 129, 30, 54, 132, +/* 7780 */ 30, 53, 129, 30, 52, 129, 30, 51, 129, 30, +/* 7790 */ 48, 129, 30, 4, 130, 193, 129, 30, 4, 80, +/* 7800 */ 4, 130, 30, 54, 136, 30, 4, 72, 5, 129, +/* 7810 */ 30, 4, 74, 5, 129, 75, 5, 129, 76, 5, +/* 7820 */ 129, 76, 6, 129, 77, 6, 130, 77, 7, 130, +/* 7830 */ 76, 8, 129, 30, 4, 75, 9, 129, 30, 4, +/* 7840 */ 72, 12, 129, 30, 54, 129, 30, 53, 130, 30, +/* 7850 */ 52, 129, 30, 51, 129, 30, 49, 129, 30, 46, +/* 7860 */ 129, 30, 42, 129, 30, 4, 130, 193, 129, 48, +/* 7870 */ 18, 129, 43, 28, 129, 41, 32, 129, 39, 36, +/* 7880 */ 129, 37, 40, 129, 35, 44, 129, 34, 46, 129, +/* 7890 */ 33, 13, 68, 13, 129, 32, 9, 73, 9, 129, +/* 7900 */ 32, 7, 75, 7, 129, 31, 6, 77, 6, 129, +/* 7910 */ 31, 5, 78, 5, 129, 30, 5, 79, 5, 129, +/* 7920 */ 30, 4, 80, 4, 132, 30, 5, 79, 5, 130, +/* 7930 */ 31, 5, 78, 5, 129, 31, 6, 77, 6, 129, +/* 7940 */ 32, 7, 75, 7, 129, 32, 9, 73, 9, 129, +/* 7950 */ 33, 13, 68, 13, 129, 34, 46, 129, 35, 44, +/* 7960 */ 129, 37, 40, 129, 39, 36, 129, 41, 32, 129, +/* 7970 */ 43, 28, 129, 48, 18, 129, 193, 129, 1, 3, +/* 7980 */ 80, 4, 130, 1, 83, 137, 37, 5, 72, 5, +/* 7990 */ 129, 35, 5, 74, 5, 129, 33, 5, 76, 5, +/* 8000 */ 129, 32, 5, 77, 5, 129, 31, 5, 78, 5, +/* 8010 */ 129, 31, 4, 79, 4, 129, 30, 5, 79, 5, +/* 8020 */ 131, 30, 6, 78, 6, 129, 30, 7, 77, 7, +/* 8030 */ 129, 31, 8, 75, 8, 129, 31, 11, 72, 11, +/* 8040 */ 129, 32, 15, 67, 15, 129, 33, 48, 129, 34, +/* 8050 */ 46, 129, 35, 44, 129, 37, 40, 129, 39, 36, +/* 8060 */ 129, 42, 30, 129, 46, 22, 129, 193, 129, 46, +/* 8070 */ 22, 129, 42, 30, 129, 39, 36, 129, 37, 40, +/* 8080 */ 129, 35, 44, 129, 34, 46, 129, 33, 48, 129, +/* 8090 */ 32, 15, 67, 15, 129, 31, 11, 72, 11, 129, +/* 8100 */ 31, 8, 75, 8, 129, 30, 7, 77, 7, 129, +/* 8110 */ 30, 6, 78, 6, 129, 30, 5, 79, 5, 131, +/* 8120 */ 31, 4, 79, 4, 129, 31, 5, 78, 5, 129, +/* 8130 */ 32, 5, 77, 5, 129, 33, 5, 76, 5, 129, +/* 8140 */ 35, 5, 74, 5, 129, 37, 5, 72, 5, 129, +/* 8150 */ 1, 83, 136, 1, 3, 80, 4, 130, 193, 129, +/* 8160 */ 30, 4, 80, 4, 130, 30, 54, 136, 30, 4, +/* 8170 */ 68, 6, 129, 30, 4, 70, 6, 129, 71, 7, +/* 8180 */ 129, 72, 7, 129, 73, 7, 129, 74, 7, 129, +/* 8190 */ 74, 8, 129, 75, 8, 130, 69, 15, 129, 67, +/* 8200 */ 17, 129, 66, 18, 129, 65, 19, 130, 65, 18, +/* 8210 */ 130, 66, 16, 129, 67, 13, 129, 69, 8, 129, +/* 8220 */ 193, 129, 30, 13, 64, 8, 129, 30, 13, 61, +/* 8230 */ 14, 129, 30, 13, 59, 18, 129, 30, 13, 57, +/* 8240 */ 22, 129, 33, 8, 56, 24, 129, 32, 7, 55, +/* 8250 */ 26, 129, 32, 6, 54, 28, 129, 31, 6, 53, +/* 8260 */ 16, 77, 6, 129, 31, 5, 53, 14, 79, 4, +/* 8270 */ 129, 30, 5, 52, 14, 80, 4, 129, 30, 5, +/* 8280 */ 52, 13, 80, 4, 129, 30, 4, 52, 13, 80, +/* 8290 */ 4, 129, 30, 4, 52, 12, 80, 4, 129, 30, +/* 8300 */ 4, 51, 13, 80, 4, 130, 30, 4, 50, 13, +/* 8310 */ 79, 5, 129, 30, 4, 50, 13, 78, 5, 129, +/* 8320 */ 30, 5, 49, 14, 77, 6, 129, 31, 4, 49, +/* 8330 */ 13, 76, 6, 129, 31, 5, 48, 14, 75, 7, +/* 8340 */ 129, 32, 5, 47, 14, 73, 8, 129, 32, 6, +/* 8350 */ 45, 16, 71, 13, 129, 33, 27, 71, 13, 129, +/* 8360 */ 34, 26, 71, 13, 129, 35, 24, 71, 13, 129, +/* 8370 */ 37, 20, 129, 39, 16, 129, 43, 9, 129, 193, +/* 8380 */ 129, 80, 4, 131, 41, 56, 129, 37, 60, 129, +/* 8390 */ 35, 62, 129, 33, 64, 129, 32, 65, 129, 31, +/* 8400 */ 66, 129, 30, 67, 130, 30, 11, 80, 4, 129, +/* 8410 */ 30, 9, 80, 4, 129, 30, 8, 80, 4, 129, +/* 8420 */ 31, 7, 80, 4, 129, 31, 6, 129, 32, 5, +/* 8430 */ 129, 33, 5, 129, 35, 4, 129, 38, 3, 129, +/* 8440 */ 193, 129, 80, 4, 130, 42, 42, 129, 38, 46, +/* 8450 */ 129, 35, 49, 129, 33, 51, 129, 32, 52, 129, +/* 8460 */ 31, 53, 130, 30, 54, 129, 30, 12, 129, 30, +/* 8470 */ 9, 129, 30, 8, 129, 30, 7, 130, 31, 6, +/* 8480 */ 130, 32, 6, 129, 33, 5, 129, 34, 5, 129, +/* 8490 */ 35, 5, 80, 4, 129, 37, 5, 80, 4, 129, +/* 8500 */ 30, 54, 136, 30, 4, 130, 193, 129, 80, 4, +/* 8510 */ 130, 77, 7, 129, 74, 10, 129, 70, 14, 129, +/* 8520 */ 66, 18, 129, 62, 22, 129, 59, 25, 129, 55, +/* 8530 */ 29, 129, 51, 33, 129, 47, 37, 129, 44, 32, +/* 8540 */ 80, 4, 129, 40, 32, 80, 4, 129, 36, 32, +/* 8550 */ 129, 32, 33, 129, 30, 31, 129, 33, 24, 129, +/* 8560 */ 36, 17, 129, 40, 12, 129, 44, 12, 129, 48, +/* 8570 */ 12, 129, 51, 13, 129, 55, 13, 129, 59, 13, +/* 8580 */ 80, 4, 129, 63, 13, 80, 4, 129, 67, 17, +/* 8590 */ 129, 71, 13, 129, 74, 10, 129, 78, 6, 129, +/* 8600 */ 80, 4, 131, 193, 129, 80, 4, 130, 77, 7, +/* 8610 */ 129, 74, 10, 129, 70, 14, 129, 66, 18, 129, +/* 8620 */ 62, 22, 129, 59, 25, 129, 55, 29, 129, 51, +/* 8630 */ 33, 129, 47, 37, 129, 44, 32, 80, 4, 129, +/* 8640 */ 40, 32, 80, 4, 129, 36, 32, 129, 32, 33, +/* 8650 */ 129, 30, 31, 129, 33, 24, 129, 36, 17, 129, +/* 8660 */ 40, 12, 129, 44, 12, 129, 47, 13, 129, 44, +/* 8670 */ 20, 129, 40, 28, 129, 36, 31, 129, 32, 32, +/* 8680 */ 129, 30, 30, 129, 33, 24, 129, 36, 17, 129, +/* 8690 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51, +/* 8700 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129, +/* 8710 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13, +/* 8720 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131, +/* 8730 */ 193, 129, 30, 4, 80, 4, 130, 30, 4, 79, +/* 8740 */ 5, 129, 30, 5, 77, 7, 129, 30, 6, 74, +/* 8750 */ 10, 129, 30, 8, 72, 12, 129, 30, 11, 69, +/* 8760 */ 15, 129, 30, 13, 67, 17, 129, 30, 4, 37, +/* 8770 */ 8, 64, 20, 129, 30, 4, 39, 8, 62, 22, +/* 8780 */ 129, 41, 8, 59, 25, 129, 43, 8, 57, 27, +/* 8790 */ 129, 45, 8, 55, 22, 80, 4, 129, 47, 27, +/* 8800 */ 80, 4, 129, 49, 23, 129, 47, 22, 129, 44, +/* 8810 */ 23, 129, 42, 22, 129, 30, 4, 39, 27, 129, +/* 8820 */ 30, 4, 37, 31, 129, 30, 27, 62, 8, 129, +/* 8830 */ 30, 25, 64, 8, 129, 30, 22, 66, 8, 80, +/* 8840 */ 4, 129, 30, 20, 68, 8, 80, 4, 129, 30, +/* 8850 */ 17, 70, 8, 80, 4, 129, 30, 15, 73, 11, +/* 8860 */ 129, 30, 12, 75, 9, 129, 30, 10, 77, 7, +/* 8870 */ 129, 30, 7, 79, 5, 129, 30, 5, 80, 4, +/* 8880 */ 129, 30, 4, 80, 4, 130, 193, 129, 4, 5, +/* 8890 */ 80, 4, 129, 2, 9, 80, 4, 129, 1, 11, +/* 8900 */ 77, 7, 129, 1, 12, 74, 10, 129, 1, 12, +/* 8910 */ 70, 14, 129, 1, 12, 66, 18, 129, 1, 11, +/* 8920 */ 62, 22, 129, 2, 9, 59, 25, 129, 4, 11, +/* 8930 */ 55, 29, 129, 7, 12, 51, 33, 129, 10, 12, +/* 8940 */ 47, 37, 129, 14, 12, 44, 32, 80, 4, 129, +/* 8950 */ 17, 13, 40, 32, 80, 4, 129, 21, 13, 36, +/* 8960 */ 32, 129, 25, 40, 129, 29, 32, 129, 33, 24, +/* 8970 */ 129, 36, 17, 129, 40, 12, 129, 44, 12, 129, +/* 8980 */ 48, 12, 129, 51, 13, 129, 55, 13, 129, 59, +/* 8990 */ 13, 80, 4, 129, 63, 13, 80, 4, 129, 67, +/* 9000 */ 17, 129, 71, 13, 129, 74, 10, 129, 78, 6, +/* 9010 */ 129, 80, 4, 131, 193, 129, 30, 1, 71, 13, +/* 9020 */ 129, 30, 3, 71, 13, 129, 30, 6, 71, 13, +/* 9030 */ 129, 30, 9, 75, 9, 129, 30, 11, 77, 7, +/* 9040 */ 129, 30, 14, 79, 5, 129, 30, 17, 79, 5, +/* 9050 */ 129, 30, 19, 80, 4, 129, 30, 22, 80, 4, +/* 9060 */ 129, 30, 25, 80, 4, 129, 30, 27, 80, 4, +/* 9070 */ 129, 30, 4, 36, 24, 80, 4, 129, 30, 4, +/* 9080 */ 38, 25, 80, 4, 129, 30, 4, 41, 24, 80, +/* 9090 */ 4, 129, 30, 4, 44, 24, 80, 4, 129, 30, +/* 9100 */ 4, 46, 25, 80, 4, 129, 30, 4, 49, 25, +/* 9110 */ 80, 4, 129, 30, 4, 52, 24, 80, 4, 129, +/* 9120 */ 30, 4, 54, 30, 129, 30, 4, 57, 27, 129, +/* 9130 */ 30, 4, 59, 25, 129, 30, 4, 62, 22, 129, +/* 9140 */ 30, 4, 65, 19, 129, 30, 5, 67, 17, 129, +/* 9150 */ 30, 5, 70, 14, 129, 30, 7, 73, 11, 129, +/* 9160 */ 30, 9, 76, 8, 129, 30, 13, 78, 6, 129, +/* 9170 */ 30, 13, 81, 3, 129, 30, 13, 129, 193, 2, +/* 9180 */ 9, 59, 25, 129, 4, 11, 55, 29, 129, 7, +/* 9190 */ 12, 51, 33, 129, 10, 12, 47, 37, 129, 14, +/* 9200 */ 12, 44, 32, 80, 4, 129, 17, 13, 40, 32, +/* 9210 */ 80, 4, 129, 21, 13, 36, 32, 129, 25, 40, +/* 9220 */ 129, 29, 32, 129, 33, 24, 129, 36, 17, 129, +/* 9230 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51, +/* 9240 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129, +/* 9250 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13, +/* 9260 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131, +/* 9270 */ 193 +}; + +char line[DWIDTH]; +char message[MAXMSG]; +char print[DWIDTH]; +int debug, i, j, linen, max, nchars, pc, term, trace, x, y; +int width = DWIDTH; /* -w option: scrunch letters to 80 columns */ + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + + while ((ch = getopt(argc, argv, "w:td")) != EOF) + switch(ch) { + case 'w': + width = atoi(optarg); + if (width <= 0) + width = 80; + break; + case 'd': + debug = 1; + break; + case 't': + trace = 1; + break; + case '?': + default: + fprintf(stderr, "usage: banner [-w width]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + for (i = 0; i < width; i++) { + j = i * 132 / width; + print[j] = 1; + } + + /* Have now read in the data. Next get the message to be printed. */ + if (*argv) { + strcpy(message, *argv); + while (*++argv) { + strcat(message, " "); + strcat(message, *argv); + } + nchars = strlen(message); + } else { + fprintf(stderr,"Message: "); + (void)fgets(message, sizeof(message), stdin); + nchars = strlen(message); + message[nchars--] = '\0'; /* get rid of newline */ + } + + /* some debugging print statements */ + if (debug) { + printf("int asc_ptr[128] = {\n"); + for (i = 0; i < 128; i++) { + printf("%4d, ",asc_ptr[i]); + if ((i+1) % 8 == 0) + printf("\n"); + } + printf("};\nchar data_table[NBYTES] = {\n"); + printf(" /* "); + for (i = 0; i < 10; i++) printf(" %3d ",i); + printf(" */\n"); + for (i = 0; i < NBYTES; i += 10) { + printf("/* %4d */ ",i); + for (j = i; j < i+10; j++) { + x = data_table[j] & 0377; + printf(" %3d, ",x); + } + putchar('\n'); + } + printf("};\n"); + } + + /* check message to make sure it's legal */ + j = 0; + for (i = 0; i < nchars; i++) + if ((u_char) message[i] >= NCHARS || + asc_ptr[(u_char) message[i]] == 0) { + warnx("The character '%c' is not in my character set", + message[i]); + j++; + } + if (j) + exit(1); + + if (trace) + printf("Message '%s' is OK\n",message); + /* Now have message. Print it one character at a time. */ + + for (i = 0; i < nchars; i++) { + if (trace) + printf("Char #%d: %c\n", i, message[i]); + for (j = 0; j < DWIDTH; j++) line[j] = ' '; + pc = asc_ptr[(u_char) message[i]]; + term = 0; + max = 0; + linen = 0; + while (!term) { + if (pc < 0 || pc > NBYTES) { + printf("bad pc: %d\n",pc); + exit(1); + } + x = data_table[pc] & 0377; + if (trace) + printf("pc=%d, term=%d, max=%d, linen=%d, x=%d\n",pc,term,max,linen,x); + if (x >= 128) { + if (x>192) term++; + x = x & 63; + while (x--) { + if (print[linen++]) { + for (j=0; j <= max; j++) + if (print[j]) + putchar(line[j]); + putchar('\n'); + } + } + for (j = 0; j < DWIDTH; j++) line[j] = ' '; + pc++; + } + else { + y = data_table[pc+1]; + /* compensate for narrow teminals */ +#ifdef notdef + x = (x*width + (DWIDTH/2)) / DWIDTH; + y = (y*width + (DWIDTH/2)) / DWIDTH; +#endif + max = x+y; + while (x < max) line[x++] = '#'; + pc += 2; + if (trace) + printf("x=%d, y=%d, max=%d\n",x,y,max); + } + } + } + + exit(0); +} diff --git a/usr.bin/basename/Makefile b/usr.bin/basename/Makefile new file mode 100644 index 0000000..21354bd --- /dev/null +++ b/usr.bin/basename/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= basename +MLINKS= basename.1 dirname.1 + +.include diff --git a/usr.bin/basename/basename.1 b/usr.bin/basename/basename.1 new file mode 100644 index 0000000..be0963c --- /dev/null +++ b/usr.bin/basename/basename.1 @@ -0,0 +1,97 @@ +.\" Copyright (c) 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)basename.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt BASENAME 1 +.Os +.Sh NAME +.Nm basename , dirname +.Nd return filename or directory portion of pathname +.Sh SYNOPSIS +.Nm basename +.Ar string +.Op Ar suffix +.Nm dirname +.Ar string +.Sh DESCRIPTION +.Nm Basename +deletes any prefix ending with the last slash +.Ql \&/ +character present in +.Ar string , +and a +.Ar suffix , +if given. +The resulting filename is written to the standard output. +If +.Ar string +ends in the slash character, +.Ql / , +or is the same as the +.Ar suffix +argument, +a newline is output. +A non-existent suffix is ignored. +.Pp +.Nm Dirname +deletes the filename portion, beginning +with the last slash +.Ql \&/ +character to the end of +.Ar string , +and writes the result to the standard output. +.Sh EXAMPLES +The following line sets the shell variable +.Ev FOO +to +.Pa /usr/bin . +.Pp +.Dl FOO=`dirname /usr/bin/trail` +.Pp +Both the +.Nm basename +and +.Nm dirname +exit 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr csh 1 +.Xr sh 1 +.Sh STANDARDS +The +.Nm basename +and +.Nm dirname +functions are expected to be POSIX 1003.2 compatible. diff --git a/usr.bin/basename/basename.c b/usr.bin/basename/basename.c new file mode 100644 index 0000000..b369190 --- /dev/null +++ b/usr.bin/basename/basename.c @@ -0,0 +1,138 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)basename.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *p; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1 && argc != 2) + usage(); + + /* + * (1) If string is // it is implementation defined whether steps (2) + * through (5) are skipped or processed. + * + * (2) If string consists entirely of slash characters, string shall + * be set to a single slash character. In this case, skip steps + * (3) through (5). + */ + for (p = *argv;; ++p) { + if (!*p) { + if (p > *argv) + (void)printf("/\n"); + else + (void)printf("\n"); + exit(0); + } + if (*p != '/') + break; + } + + /* + * (3) If there are any trailing slash characters in string, they + * shall be removed. + */ + for (; *p; ++p) + continue; + while (*--p == '/') + continue; + *++p = '\0'; + + /* + * (4) If there are any slash characters remaining in string, the + * prefix of string up to an including the last slash character + * in string shall be removed. + */ + while (--p >= *argv) + if (*p == '/') + break; + ++p; + + /* + * (5) If the suffix operand is present, is not identical to the + * characters remaining in string, and is identical to a suffix + * of the characters remaining in string, the suffix suffix + * shall be removed from string. + */ + if (*++argv) { + int suffixlen, stringlen, off; + + suffixlen = strlen(*argv); + stringlen = strlen(p); + + if (suffixlen < stringlen) { + off = stringlen - suffixlen; + if (!strcmp(p + off, *argv)) + p[off] = '\0'; + } + } + (void)printf("%s\n", p); + exit(0); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: basename string [suffix]\n"); + exit(1); +} diff --git a/usr.bin/bdes/Makefile b/usr.bin/bdes/Makefile new file mode 100644 index 0000000..9166f72 --- /dev/null +++ b/usr.bin/bdes/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= bdes + +.include diff --git a/usr.bin/bdes/bdes.1 b/usr.bin/bdes/bdes.1 new file mode 100644 index 0000000..eecd81b --- /dev/null +++ b/usr.bin/bdes/bdes.1 @@ -0,0 +1,304 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Matt Bishop of Dartmouth College. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)bdes.1 8.1 (Berkeley) 6/29/93 +.\" +.TH BDES 1 "June 29, 1993" +.UC 6 +.SH NAME +bdes \- encrypt/decrypt using the Data Encryption Standard +.SH SYNOPSIS +.nf +.ft B +bdes [ \-abdp ] [ \-F N ] [ \-f N ] [ \-k key ] +.ti +5 +[ \-m N ] [ \-o N ] [ \-v vector ] +.ft R +.fi +.SH DESCRIPTION +.I Bdes +implements all DES modes of operation described in FIPS PUB 81, +including alternative cipher feedback mode and both authentication +modes. +.I Bdes +reads from the standard input and writes to the standard output. +By default, the input is encrypted using cipher block chaining mode. +Using the same key for encryption and decryption preserves plain text. +.PP +All modes but the electronic code book mode require an initialization +vector; if none is supplied, the zero vector is used. +If no +.I key +is specified on the command line, the user is prompted for one (see +.IR getpass (3) +for more details). +.PP +The options are as follows: +.TP +\-a +The key and initialization vector strings are to be taken as ASCII, +suppressing the special interpretation given to leading ``0X'', ``0x'', +``0B'', and ``0b'' characters. +This flag applies to +.I both +the key and initialization vector. +.TP +\-b +Use electronic code book mode. +.TP +\-d +Decrypt the input. +.TP +\-F +Use +.IR N -bit +alternative cipher feedback mode. +Currently +.I N +must be a multiple of 7 between 7 and 56 inclusive (this does not conform +to the alternative CFB mode specification). +.TP +\-f +Use +.IR N -bit +cipher feedback mode. +Currently +.I N +must be a multiple of 8 between 8 and 64 inclusive (this does not conform +to the standard CFB mode specification). +.TP +\-k +Use +.I key +as the cryptographic key. +.TP +\-m +Compute a message authentication code (MAC) of +.I N +bits on the input. +The value of +.I N +must be between 1 and 64 inclusive; if +.I N +is not a multiple of 8, enough 0 bits will be added to pad the MAC length +to the nearest multiple of 8. +Only the MAC is output. +MACs are only available in cipher block chaining mode or in cipher feedback +mode. +.TP +\-o +Use +.IR N -bit +output feedback mode. +Currently +.I N +must be a multiple of 8 between 8 and 64 inclusive (this does not conform +to the OFB mode specification). +.TP +\-p +Disable the resetting of the parity bit. +This flag forces the parity bit of the key to be used as typed, rather than +making each character be of odd parity. +It is used only if the key is given in ASCII. +.TP +\-v +Set the initialization vector to +.IR vector ; +the vector is interpreted in the same way as the key. +The vector is ignored in electronic codebook mode. +.PP +The key and initialization vector are taken as sequences of ASCII +characters which are then mapped into their bit representations. +If either begins with ``0X'' or ``0x'', +that one is taken as a sequence of hexadecimal digits indicating the +bit pattern; +if either begins with ``0B'' or ``0b'', +that one is taken as a sequence of binary digits indicating the bit pattern. +In either case, +only the leading 64 bits of the key or initialization vector +are used, +and if fewer than 64 bits are provided, enough 0 bits are appended +to pad the key to 64 bits. +.PP +According to the DES standard, the low-order bit of each character in the +key string is deleted. +Since most ASCII representations set the high-order bit to 0, simply +deleting the low-order bit effectively reduces the size of the key space +from 2\u\s-356\s0\d to 2\u\s-348\s0\d keys. +To prevent this, the high-order bit must be a function depending in part +upon the low-order bit; so, the high-order bit is set to whatever value +gives odd parity. +This preserves the key space size. +Note this resetting of the parity bit is +.I not +done if the key is given in binary or hex, and can be disabled for ASCII +keys as well. +.PP +The DES is considered a very strong cryptosystem, and other than table lookup +attacks, key search attacks, and Hellman's time-memory tradeoff (all of which +are very expensive and time-consuming), no cryptanalytic methods for breaking +the DES are known in the open literature. +No doubt the choice of keys and key security are the most vulnerable aspect +of +.IR bdes . +.SH IMPLEMENTATION NOTES +For implementors wishing to write software compatible with this program, +the following notes are provided. +This software is believed to be compatible with the implementation of the +data encryption standard distributed by Sun Microsystems, Inc. +.PP +In the ECB and CBC modes, plaintext is encrypted in units of 64 bits (8 bytes, +also called a block). +To ensure that the plaintext file is encrypted correctly, +.I bdes +will (internally) append from 1 to 8 bytes, the last byte containing an +integer stating how many bytes of that final block are from the plaintext +file, and encrypt the resulting block. +Hence, when decrypting, the last block may contain from 0 to 7 characters +present in the plaintext file, and the last byte tells how many. +Note that if during decryption the last byte of the file does not contain an +integer between 0 and 7, either the file has been corrupted or an incorrect +key has been given. +A similar mechanism is used for the OFB and CFB modes, except that those +simply require the length of the input to be a multiple of the mode size, +and the final byte contains an integer between 0 and one less than the number +of bytes being used as the mode. +(This was another reason that the mode size must be a multiple of 8 for those +modes.) +.PP +Unlike Sun's implementation, unused bytes of that last block are not filled +with random data, but instead contain what was in those byte positions in +the preceding block. +This is quicker and more portable, and does not weaken the encryption +significantly. +.PP +If the key is entered in ASCII, the parity bits of the key characters are set +so that each key character is of odd parity. +Unlike Sun's implementation, it is possible to enter binary or hexadecimal +keys on the command line, and if this is done, the parity bits are +.I not +reset. +This allows testing using arbitrary bit patterns as keys. +.PP +The Sun implementation always uses an initialization vector of 0 +(that is, all zeroes). +By default, +.I bdes +does too, but this may be changed from the command line. +.SH SEE ALSO +crypt(1), crypt(3), getpass(3) +.sp +.IR "Data Encryption Standard" , +Federal Information Processing Standard #46, +National Bureau of Standards, +U.S. Department of Commerce, +Washington DC +(Jan. 1977) +.sp +.IR "DES Modes of Operation" , +Federal Information Processing Standard #81, +National Bureau of Standards, +U.S. Department of Commerce +Washington DC +(Dec. 1980) +.sp +Dorothy Denning, +.IR "Cryptography and Data Security" , +Addison-Wesley Publishing Co., +Reading, MA +\(co1982. +.sp +Matt Bishop, +.IR "Implementation Notes on bdes(1)" , +Technical Report PCS-TR-91-158, +Department of Mathematics and Computer Science, +Dartmouth College, +Hanover, NH 03755 +(Apr. 1991). +.SH DISCLAIMER +.nf +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +.fi +.SH BUGS +There is a controversy raging over whether the DES will still be secure +in a few years. +The advent of special-purpose hardware could reduce the cost of any of the +methods of attack named above so that they are no longer computationally +infeasible. +.PP +As the key or key schedule is stored in memory, the encryption can be +compromised if memory is readable. +Additionally, programs which display programs' arguments may compromise the +key and initialization vector, if they are specified on the command line. +To avoid this +.I bdes +overwrites its arguments, however, the obvious race cannot currently be +avoided. +.PP +Certain specific keys should be avoided because they introduce potential +weaknesses; these keys, called the +.I weak +and +.I semiweak +keys, are (in hex notation, where p is either 0 or 1, and P is either +e or f): +.sp +.nf +.in +10n +.ta \w'0x0p0p0p0p0p0p0p0p\0\0\0'u+5n +0x0p0p0p0p0p0p0p0p 0x0p1P0p1P0p0P0p0P +0x0pep0pep0pfp0pfp 0x0pfP0pfP0pfP0pfP +0x1P0p1P0p0P0p0P0p 0x1P1P1P1P0P0P0P0P +0x1Pep1Pep0Pfp0Pfp 0x1PfP1PfP0PfP0PfP +0xep0pep0pfp0pfp0p 0xep1Pep1pfp0Pfp0P +0xepepepepepepepep 0xepfPepfPfpfPfpfP +0xfP0pfP0pfP0pfP0p 0xfP1PfP1PfP0PfP0P +0xfPepfPepfPepfPep 0xfPfPfPfPfPfPfPfP +.fi +.in -10n +.sp +This is inherent in the DES algorithm (see Moore and Simmons, +\*(LqCycle structure of the DES with weak and semi-weak keys,\*(Rq +.I "Advances in Cryptology \- Crypto '86 Proceedings" , +Springer-Verlag New York, \(co1987, pp. 9-32.) diff --git a/usr.bin/bdes/bdes.c b/usr.bin/bdes/bdes.c new file mode 100644 index 0000000..f702e01 --- /dev/null +++ b/usr.bin/bdes/bdes.c @@ -0,0 +1,1046 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Matt Bishop of Dartmouth College. + * + * The United States Government has rights in this work pursuant + * to contract no. NAG 2-680 between the National Aeronautics and + * Space Administration and Dartmouth College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)bdes.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * BDES -- DES encryption package for Berkeley Software Distribution 4.4 + * options: + * -a key is in ASCII + * -b use ECB (electronic code book) mode + * -d invert (decrypt) input + * -f b use b-bit CFB (cipher feedback) mode + * -F b use b-bit CFB (cipher feedback) alternative mode + * -k key use key as the cryptographic key + * -m b generate a MAC of length b + * -o b use b-bit OFB (output feedback) mode + * -p don't reset the parity bit + * -v v use v as the initialization vector (ignored for ECB) + * note: the last character of the last block is the integer indicating + * how many characters of that block are to be output + * + * Author: Matt Bishop + * Department of Mathematics and Computer Science + * Dartmouth College + * Hanover, NH 03755 + * Email: Matt.Bishop@dartmouth.edu + * ...!decvax!dartvax!Matt.Bishop + * + * See Technical Report PCS-TR91-158, Department of Mathematics and Computer + * Science, Dartmouth College, for a detailed description of the implemen- + * tation and differences between it and Sun's. The DES is described in + * FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page + * or the technical report for a complete reference). + */ + +#include +#include +#include +#include +#include +#include + +/* + * BSD and System V systems offer special library calls that do + * block moves and fills, so if possible we take advantage of them + */ +#define MEMCPY(dest,src,len) bcopy((src),(dest),(len)) +#define MEMZERO(dest,len) bzero((dest),(len)) + +/* Hide the calls to the primitive encryption routines. */ +#define FASTWAY +#ifdef FASTWAY +#define DES_KEY(buf) \ + if (des_setkey(buf)) \ + err("des_setkey", 0); +#define DES_XFORM(buf) \ + if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \ + err("des_cipher", 0); +#else +#define DES_KEY(buf) { \ + char bits1[64]; /* bits of key */ \ + expand(buf, bits1); \ + if (setkey(bits1)) \ + err("setkey", 0); \ + } +#define DES_XFORM(buf) { \ + char bits1[64]; /* bits of message */ \ + expand(buf, bits1); \ + if (encrypt(bits1, inverse)) \ + err("encrypt", 0); \ + compress(bits1, buf); \ + } +#endif + +/* + * this does an error-checking write + */ +#define READ(buf, n) fread(buf, sizeof(char), n, stdin) +#define WRITE(buf,n) \ + if (fwrite(buf, sizeof(char), n, stdout) != n) \ + err(bn, NULL); + +/* + * some things to make references easier + */ +typedef char Desbuf[8]; +#define CHAR(x,i) (x[i]) +#define UCHAR(x,i) (x[i]) +#define BUFFER(x) (x) +#define UBUFFER(x) (x) + +/* + * global variables and related macros + */ +#define KEY_DEFAULT 0 /* interpret radix of key from key */ +#define KEY_ASCII 1 /* key is in ASCII characters */ +int keybase = KEY_DEFAULT; /* how to interpret the key */ + +enum { /* encrypt, decrypt, authenticate */ + MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE +} mode = MODE_ENCRYPT; +enum { /* ecb, cbc, cfb, cfba, ofb? */ + ALG_ECB, ALG_CBC, ALG_CFB, ALG_OFB, ALG_CFBA +} alg = ALG_CBC; + +Desbuf ivec; /* initialization vector */ +char bits[] = { /* used to extract bits from a char */ + '\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001' +}; +int inverse; /* 0 to encrypt, 1 to decrypt */ +int macbits = -1; /* number of bits in authentication */ +int fbbits = -1; /* number of feedback bits */ +int pflag; /* 1 to preserve parity bits */ + +main(ac, av) + int ac; /* arg count */ + char **av; /* arg vector */ +{ + extern int optind; /* option (argument) number */ + extern char *optarg; /* argument to option if any */ + register int i; /* counter in a for loop */ + register char *p; /* used to obtain the key */ + Desbuf msgbuf; /* I/O buffer */ + int kflag; /* command-line encryptiooon key */ + int argc; /* the real arg count */ + char **argv; /* the real argument vector */ + + /* + * Hide the arguments from ps(1) by making private copies of them + * and clobbering the global (visible to ps(1)) ones. + */ + argc = ac; + ac = 1; + argv = malloc((argc + 1) * sizeof(char *)); + for (i = 0; i < argc; ++i) { + argv[i] = strdup(av[i]); + MEMZERO(av[i], strlen(av[i])); + } + argv[argc] = NULL; + + /* initialize the initialization vctor */ + MEMZERO(ivec, 8); + + /* process the argument list */ + kflag = 0; + while ((i = getopt(argc, argv, "abdF:f:k:m:o:pv:")) != EOF) + switch(i) { + case 'a': /* key is ASCII */ + keybase = KEY_ASCII; + break; + case 'b': /* use ECB mode */ + alg = ALG_ECB; + break; + case 'd': /* decrypt */ + mode = MODE_DECRYPT; + break; + case 'F': /* use alternative CFB mode */ + alg = ALG_CFBA; + if ((fbbits = setbits(optarg, 7)) > 56 || fbbits == 0) + err(-1, "-F: number must be 1-56 inclusive"); + else if (fbbits == -1) + err(-1, "-F: number must be a multiple of 7"); + break; + case 'f': /* use CFB mode */ + alg = ALG_CFB; + if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0) + err(-1, "-f: number must be 1-64 inclusive"); + else if (fbbits == -1) + err(-1, "-f: number must be a multiple of 8"); + break; + case 'k': /* encryption key */ + kflag = 1; + cvtkey(BUFFER(msgbuf), optarg); + break; + case 'm': /* number of bits for MACing */ + mode = MODE_AUTHENTICATE; + if ((macbits = setbits(optarg, 1)) > 64) + err(-1, "-m: number must be 0-64 inclusive"); + break; + case 'o': /* use OFB mode */ + alg = ALG_OFB; + if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0) + err(-1, "-o: number must be 1-64 inclusive"); + else if (fbbits == -1) + err(-1, "-o: number must be a multiple of 8"); + break; + case 'p': /* preserve parity bits */ + pflag = 1; + break; + case 'v': /* set initialization vector */ + cvtkey(BUFFER(ivec), optarg); + break; + default: /* error */ + usage(); + } + + if (!kflag) { + /* + * if the key's not ASCII, assume it is + */ + keybase = KEY_ASCII; + /* + * get the key + */ + p = getpass("Enter key: "); + /* + * copy it, nul-padded, into the key area + */ + cvtkey(BUFFER(msgbuf), p); + } + + makekey(msgbuf); + inverse = (alg == ALG_CBC || alg == ALG_ECB) && mode == MODE_DECRYPT; + + switch(alg) { + case ALG_CBC: + switch(mode) { + case MODE_AUTHENTICATE: /* authenticate using CBC mode */ + cbcauth(); + break; + case MODE_DECRYPT: /* decrypt using CBC mode */ + cbcdec(); + break; + case MODE_ENCRYPT: /* encrypt using CBC mode */ + cbcenc(); + break; + } + break; + case ALG_CFB: + switch(mode) { + case MODE_AUTHENTICATE: /* authenticate using CFB mode */ + cfbauth(); + break; + case MODE_DECRYPT: /* decrypt using CFB mode */ + cfbdec(); + break; + case MODE_ENCRYPT: /* encrypt using CFB mode */ + cfbenc(); + break; + } + break; + case ALG_CFBA: + switch(mode) { + case MODE_AUTHENTICATE: /* authenticate using CFBA mode */ + err(-1, "can't authenticate with CFBA mode"); + break; + case MODE_DECRYPT: /* decrypt using CFBA mode */ + cfbadec(); + break; + case MODE_ENCRYPT: /* encrypt using CFBA mode */ + cfbaenc(); + break; + } + break; + case ALG_ECB: + switch(mode) { + case MODE_AUTHENTICATE: /* authenticate using ECB mode */ + err(-1, "can't authenticate with ECB mode"); + break; + case MODE_DECRYPT: /* decrypt using ECB mode */ + ecbdec(); + break; + case MODE_ENCRYPT: /* encrypt using ECB mode */ + ecbenc(); + break; + } + break; + case ALG_OFB: + switch(mode) { + case MODE_AUTHENTICATE: /* authenticate using OFB mode */ + err(-1, "can't authenticate with OFB mode"); + break; + case MODE_DECRYPT: /* decrypt using OFB mode */ + ofbdec(); + break; + case MODE_ENCRYPT: /* encrypt using OFB mode */ + ofbenc(); + break; + } + break; + } + exit(0); +} + +/* + * print a warning message and, possibly, terminate + */ +err(n, s) + int n; /* offending block number */ + char *s; /* the message */ +{ + if (n > 0) + (void)fprintf(stderr, "bdes (block %d): ", n); + else + (void)fprintf(stderr, "bdes: "); + (void)fprintf(stderr, "%s\n", s ? s : strerror(errno)); + exit(1); +} + +/* + * map a hex character to an integer + */ +tobinhex(c, radix) + char c; /* char to be converted */ + int radix; /* base (2 to 16) */ +{ + switch(c) { + case '0': return(0x0); + case '1': return(0x1); + case '2': return(radix > 2 ? 0x2 : -1); + case '3': return(radix > 3 ? 0x3 : -1); + case '4': return(radix > 4 ? 0x4 : -1); + case '5': return(radix > 5 ? 0x5 : -1); + case '6': return(radix > 6 ? 0x6 : -1); + case '7': return(radix > 7 ? 0x7 : -1); + case '8': return(radix > 8 ? 0x8 : -1); + case '9': return(radix > 9 ? 0x9 : -1); + case 'A': case 'a': return(radix > 10 ? 0xa : -1); + case 'B': case 'b': return(radix > 11 ? 0xb : -1); + case 'C': case 'c': return(radix > 12 ? 0xc : -1); + case 'D': case 'd': return(radix > 13 ? 0xd : -1); + case 'E': case 'e': return(radix > 14 ? 0xe : -1); + case 'F': case 'f': return(radix > 15 ? 0xf : -1); + } + /* + * invalid character + */ + return(-1); +} + +/* + * convert the key to a bit pattern + */ +cvtkey(obuf, ibuf) + char *obuf; /* bit pattern */ + char *ibuf; /* the key itself */ +{ + register int i, j; /* counter in a for loop */ + int nbuf[64]; /* used for hex/key translation */ + + /* + * just switch on the key base + */ + switch(keybase) { + case KEY_ASCII: /* ascii to integer */ + (void)strncpy(obuf, ibuf, 8); + return; + case KEY_DEFAULT: /* tell from context */ + /* + * leading '0x' or '0X' == hex key + */ + if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'X')) { + ibuf = &ibuf[2]; + /* + * now translate it, bombing on any illegal hex digit + */ + for (i = 0; ibuf[i] && i < 16; i++) + if ((nbuf[i] = tobinhex(ibuf[i], 16)) == -1) + err(-1, "bad hex digit in key"); + while (i < 16) + nbuf[i++] = 0; + for (i = 0; i < 8; i++) + obuf[i] = + ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf); + /* preserve parity bits */ + pflag = 1; + return; + } + /* + * leading '0b' or '0B' == binary key + */ + if (ibuf[0] == '0' && (ibuf[1] == 'b' || ibuf[1] == 'B')) { + ibuf = &ibuf[2]; + /* + * now translate it, bombing on any illegal binary digit + */ + for (i = 0; ibuf[i] && i < 16; i++) + if ((nbuf[i] = tobinhex(ibuf[i], 2)) == -1) + err(-1, "bad binary digit in key"); + while (i < 64) + nbuf[i++] = 0; + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + obuf[i] = (obuf[i]<<1)|nbuf[8*i+j]; + /* preserve parity bits */ + pflag = 1; + return; + } + /* + * no special leader -- ASCII + */ + (void)strncpy(obuf, ibuf, 8); + } +} + +/* + * convert an ASCII string into a decimal number: + * 1. must be between 0 and 64 inclusive + * 2. must be a valid decimal number + * 3. must be a multiple of mult + */ +setbits(s, mult) + char *s; /* the ASCII string */ + int mult; /* what it must be a multiple of */ +{ + register char *p; /* pointer in a for loop */ + register int n = 0; /* the integer collected */ + + /* + * skip white space + */ + while (isspace(*s)) + s++; + /* + * get the integer + */ + for (p = s; *p; p++) { + if (isdigit(*p)) + n = n * 10 + *p - '0'; + else { + err(-1, "bad decimal digit in MAC length"); + } + } + /* + * be sure it's a multiple of mult + */ + return((n % mult != 0) ? -1 : n); +} + +/***************** + * DES FUNCTIONS * + *****************/ +/* + * This sets the DES key and (if you're using the deszip version) + * the direction of the transformation. This uses the Sun + * to map the 64-bit key onto the 56 bits that the key schedule + * generation routines use: the old way, which just uses the user- + * supplied 64 bits as is, and the new way, which resets the parity + * bit to be the same as the low-order bit in each character. The + * new way generates a greater variety of key schedules, since many + * systems set the parity (high) bit of each character to 0, and the + * DES ignores the low order bit of each character. + */ +makekey(buf) + Desbuf buf; /* key block */ +{ + register int i, j; /* counter in a for loop */ + register int par; /* parity counter */ + + /* + * if the parity is not preserved, flip it + */ + if (!pflag) { + for (i = 0; i < 8; i++) { + par = 0; + for (j = 1; j < 8; j++) + if ((bits[j]&UCHAR(buf, i)) != 0) + par++; + if ((par&01) == 01) + UCHAR(buf, i) = UCHAR(buf, i)&0177; + else + UCHAR(buf, i) = (UCHAR(buf, i)&0177)|0200; + } + } + + DES_KEY(UBUFFER(buf)); +} + +/* + * This encrypts using the Electronic Code Book mode of DES + */ +ecbenc() +{ + register int n; /* number of bytes actually read */ + register int bn; /* block number */ + Desbuf msgbuf; /* I/O buffer */ + + for (bn = 0; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++) { + /* + * do the transformation + */ + DES_XFORM(UBUFFER(msgbuf)); + WRITE(BUFFER(msgbuf), 8); + } + /* + * at EOF or last block -- in either ase, the last byte contains + * the character representation of the number of bytes in it + */ + bn++; + MEMZERO(&CHAR(msgbuf, n), 8 - n); + CHAR(msgbuf, 7) = n; + DES_XFORM(UBUFFER(msgbuf)); + WRITE(BUFFER(msgbuf), 8); + +} + +/* + * This decrypts using the Electronic Code Book mode of DES + */ +ecbdec() +{ + register int n; /* number of bytes actually read */ + register int c; /* used to test for EOF */ + register int bn; /* block number */ + Desbuf msgbuf; /* I/O buffer */ + + for (bn = 1; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++) { + /* + * do the transformation + */ + DES_XFORM(UBUFFER(msgbuf)); + /* + * if the last one, handle it specially + */ + if ((c = getchar()) == EOF) { + n = CHAR(msgbuf, 7); + if (n < 0 || n > 7) + err(bn, "decryption failed (block corrupted)"); + } + else + (void)ungetc(c, stdin); + WRITE(BUFFER(msgbuf), n); + } + if (n > 0) + err(bn, "decryption failed (incomplete block)"); +} + +/* + * This encrypts using the Cipher Block Chaining mode of DES + */ +cbcenc() +{ + register int n; /* number of bytes actually read */ + register int bn; /* block number */ + Desbuf msgbuf; /* I/O buffer */ + + /* + * do the transformation + */ + for (bn = 1; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++) { + for (n = 0; n < 8; n++) + CHAR(msgbuf, n) ^= CHAR(ivec, n); + DES_XFORM(UBUFFER(msgbuf)); + MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8); + WRITE(BUFFER(msgbuf), 8); + } + /* + * at EOF or last block -- in either case, the last byte contains + * the character representation of the number of bytes in it + */ + bn++; + MEMZERO(&CHAR(msgbuf, n), 8 - n); + CHAR(msgbuf, 7) = n; + for (n = 0; n < 8; n++) + CHAR(msgbuf, n) ^= CHAR(ivec, n); + DES_XFORM(UBUFFER(msgbuf)); + WRITE(BUFFER(msgbuf), 8); + +} + +/* + * This decrypts using the Cipher Block Chaining mode of DES + */ +cbcdec() +{ + register int n; /* number of bytes actually read */ + Desbuf msgbuf; /* I/O buffer */ + Desbuf ibuf; /* temp buffer for initialization vector */ + register int c; /* used to test for EOF */ + register int bn; /* block number */ + + for (bn = 0; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++) { + /* + * do the transformation + */ + MEMCPY(BUFFER(ibuf), BUFFER(msgbuf), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (c = 0; c < 8; c++) + UCHAR(msgbuf, c) ^= UCHAR(ivec, c); + MEMCPY(BUFFER(ivec), BUFFER(ibuf), 8); + /* + * if the last one, handle it specially + */ + if ((c = getchar()) == EOF) { + n = CHAR(msgbuf, 7); + if (n < 0 || n > 7) + err(bn, "decryption failed (block corrupted)"); + } + else + (void)ungetc(c, stdin); + WRITE(BUFFER(msgbuf), n); + } + if (n > 0) + err(bn, "decryption failed (incomplete block)"); +} + +/* + * This authenticates using the Cipher Block Chaining mode of DES + */ +cbcauth() +{ + register int n, j; /* number of bytes actually read */ + Desbuf msgbuf; /* I/O buffer */ + Desbuf encbuf; /* encryption buffer */ + + /* + * do the transformation + * note we DISCARD the encrypted block; + * we only care about the last one + */ + while ((n = READ(BUFFER(msgbuf), 8)) == 8) { + for (n = 0; n < 8; n++) + CHAR(encbuf, n) = CHAR(msgbuf, n) ^ CHAR(ivec, n); + DES_XFORM(UBUFFER(encbuf)); + MEMCPY(BUFFER(ivec), BUFFER(encbuf), 8); + } + /* + * now compute the last one, right padding with '\0' if need be + */ + if (n > 0) { + MEMZERO(&CHAR(msgbuf, n), 8 - n); + for (n = 0; n < 8; n++) + CHAR(encbuf, n) = CHAR(msgbuf, n) ^ CHAR(ivec, n); + DES_XFORM(UBUFFER(encbuf)); + } + /* + * drop the bits + * we write chars until fewer than 7 bits, + * and then pad the last one with 0 bits + */ + for (n = 0; macbits > 7; n++, macbits -= 8) + (void)putchar(CHAR(encbuf, n)); + if (macbits > 0) { + CHAR(msgbuf, 0) = 0x00; + for (j = 0; j < macbits; j++) + CHAR(msgbuf, 0) |= (CHAR(encbuf, n)&bits[j]); + (void)putchar(CHAR(msgbuf, 0)); + } +} + +/* + * This encrypts using the Cipher FeedBack mode of DES + */ +cfbenc() +{ + register int n; /* number of bytes actually read */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 8; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < 8 - nbytes; n++) + UCHAR(ivec, n) = UCHAR(ivec, n+nbytes); + for (n = 0; n < nbytes; n++) + UCHAR(ivec, 8-nbytes+n) = ibuf[n] ^ UCHAR(msgbuf, n); + WRITE(&CHAR(ivec, 8-nbytes), nbytes); + } + /* + * at EOF or last block -- in either case, the last byte contains + * the character representation of the number of bytes in it + */ + bn++; + MEMZERO(&ibuf[n], nbytes - n); + ibuf[nbytes - 1] = n; + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < nbytes; n++) + ibuf[n] ^= UCHAR(msgbuf, n); + WRITE(ibuf, nbytes); +} + +/* + * This decrypts using the Cipher Block Chaining mode of DES + */ +cfbdec() +{ + register int n; /* number of bytes actually read */ + register int c; /* used to test for EOF */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + char obuf[8]; /* output buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 8; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (c = 0; c < 8 - nbytes; c++) + CHAR(ivec, c) = CHAR(ivec, c+nbytes); + for (c = 0; c < nbytes; c++) { + CHAR(ivec, 8-nbytes+c) = ibuf[c]; + obuf[c] = ibuf[c] ^ UCHAR(msgbuf, c); + } + /* + * if the last one, handle it specially + */ + if ((c = getchar()) == EOF) { + n = obuf[nbytes-1]; + if (n < 0 || n > nbytes-1) + err(bn, "decryption failed (block corrupted)"); + } + else + (void)ungetc(c, stdin); + WRITE(obuf, n); + } + if (n > 0) + err(bn, "decryption failed (incomplete block)"); +} + +/* + * This encrypts using the alternative Cipher FeedBack mode of DES + */ +cfbaenc() +{ + register int n; /* number of bytes actually read */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + char obuf[8]; /* output buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 7; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < 8 - nbytes; n++) + UCHAR(ivec, n) = UCHAR(ivec, n+nbytes); + for (n = 0; n < nbytes; n++) + UCHAR(ivec, 8-nbytes+n) = (ibuf[n] ^ UCHAR(msgbuf, n)) + |0200; + for (n = 0; n < nbytes; n++) + obuf[n] = CHAR(ivec, 8-nbytes+n)&0177; + WRITE(obuf, nbytes); + } + /* + * at EOF or last block -- in either case, the last byte contains + * the character representation of the number of bytes in it + */ + bn++; + MEMZERO(&ibuf[n], nbytes - n); + ibuf[nbytes - 1] = ('0' + n)|0200; + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < nbytes; n++) + ibuf[n] ^= UCHAR(msgbuf, n); + WRITE(ibuf, nbytes); +} + +/* + * This decrypts using the alternative Cipher Block Chaining mode of DES + */ +cfbadec() +{ + register int n; /* number of bytes actually read */ + register int c; /* used to test for EOF */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + char obuf[8]; /* output buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 7; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (c = 0; c < 8 - nbytes; c++) + CHAR(ivec, c) = CHAR(ivec, c+nbytes); + for (c = 0; c < nbytes; c++) { + CHAR(ivec, 8-nbytes+c) = ibuf[c]|0200; + obuf[c] = (ibuf[c] ^ UCHAR(msgbuf, c))&0177; + } + /* + * if the last one, handle it specially + */ + if ((c = getchar()) == EOF) { + if ((n = (obuf[nbytes-1] - '0')) < 0 + || n > nbytes-1) + err(bn, "decryption failed (block corrupted)"); + } + else + (void)ungetc(c, stdin); + WRITE(obuf, n); + } + if (n > 0) + err(bn, "decryption failed (incomplete block)"); +} + + +/* + * This encrypts using the Output FeedBack mode of DES + */ +ofbenc() +{ + register int n; /* number of bytes actually read */ + register int c; /* used to test for EOF */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + char obuf[8]; /* output buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 8; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < 8 - nbytes; n++) + UCHAR(ivec, n) = UCHAR(ivec, n+nbytes); + for (n = 0; n < nbytes; n++) { + UCHAR(ivec, 8-nbytes+n) = UCHAR(msgbuf, n); + obuf[n] = ibuf[n] ^ UCHAR(msgbuf, n); + } + WRITE(obuf, nbytes); + } + /* + * at EOF or last block -- in either case, the last byte contains + * the character representation of the number of bytes in it + */ + bn++; + MEMZERO(&ibuf[n], nbytes - n); + ibuf[nbytes - 1] = n; + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (c = 0; c < nbytes; c++) + ibuf[c] ^= UCHAR(msgbuf, c); + WRITE(ibuf, nbytes); +} + +/* + * This decrypts using the Output Block Chaining mode of DES + */ +ofbdec() +{ + register int n; /* number of bytes actually read */ + register int c; /* used to test for EOF */ + register int nbytes; /* number of bytes to read */ + register int bn; /* block number */ + char ibuf[8]; /* input buffer */ + char obuf[8]; /* output buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 8; + /* + * do the transformation + */ + for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (c = 0; c < 8 - nbytes; c++) + CHAR(ivec, c) = CHAR(ivec, c+nbytes); + for (c = 0; c < nbytes; c++) { + CHAR(ivec, 8-nbytes+c) = UCHAR(msgbuf, c); + obuf[c] = ibuf[c] ^ UCHAR(msgbuf, c); + } + /* + * if the last one, handle it specially + */ + if ((c = getchar()) == EOF) { + n = obuf[nbytes-1]; + if (n < 0 || n > nbytes-1) + err(bn, "decryption failed (block corrupted)"); + } + else + (void)ungetc(c, stdin); + /* + * dump it + */ + WRITE(obuf, n); + } + if (n > 0) + err(bn, "decryption failed (incomplete block)"); +} + +/* + * This authenticates using the Cipher FeedBack mode of DES + */ +cfbauth() +{ + register int n, j; /* number of bytes actually read */ + register int nbytes; /* number of bytes to read */ + char ibuf[8]; /* input buffer */ + Desbuf msgbuf; /* encryption buffer */ + + /* + * do things in bytes, not bits + */ + nbytes = fbbits / 8; + /* + * do the transformation + */ + while ((n = READ(ibuf, nbytes)) == nbytes) { + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < 8 - nbytes; n++) + UCHAR(ivec, n) = UCHAR(ivec, n+nbytes); + for (n = 0; n < nbytes; n++) + UCHAR(ivec, 8-nbytes+n) = ibuf[n] ^ UCHAR(msgbuf, n); + } + /* + * at EOF or last block -- in either case, the last byte contains + * the character representation of the number of bytes in it + */ + MEMZERO(&ibuf[n], nbytes - n); + ibuf[nbytes - 1] = '0' + n; + MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8); + DES_XFORM(UBUFFER(msgbuf)); + for (n = 0; n < nbytes; n++) + ibuf[n] ^= UCHAR(msgbuf, n); + /* + * drop the bits + * we write chars until fewer than 7 bits, + * and then pad the last one with 0 bits + */ + for (n = 0; macbits > 7; n++, macbits -= 8) + (void)putchar(CHAR(msgbuf, n)); + if (macbits > 0) { + CHAR(msgbuf, 0) = 0x00; + for (j = 0; j < macbits; j++) + CHAR(msgbuf, 0) |= (CHAR(msgbuf, n)&bits[j]); + (void)putchar(CHAR(msgbuf, 0)); + } +} + +#ifndef FASTWAY +/* + * change from 8 bits/Uchar to 1 bit/Uchar + */ +expand(from, to) + Desbuf from; /* 8bit/unsigned char string */ + char *to; /* 1bit/char string */ +{ + register int i, j; /* counters in for loop */ + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + *to++ = (CHAR(from, i)>>(7-j))&01; +} + +/* + * change from 1 bit/char to 8 bits/Uchar + */ +compress(from, to) + char *from; /* 1bit/char string */ + Desbuf to; /* 8bit/unsigned char string */ +{ + register int i, j; /* counters in for loop */ + + for (i = 0; i < 8; i++) { + CHAR(to, i) = 0; + for (j = 0; j < 8; j++) + CHAR(to, i) = ((*from++)<<(7-j))|CHAR(to, i); + } +} +#endif + +/* + * message about usage + */ +usage() +{ + (void)fprintf(stderr, "%s\n", +"usage: bdes [-abdp] [-F bit] [-f bit] [-k key] [-m bit] [-o bit] [-v vector]"); + exit(1); +} diff --git a/usr.bin/bdes/bdes.ps b/usr.bin/bdes/bdes.ps new file mode 100644 index 0000000..471c267 --- /dev/null +++ b/usr.bin/bdes/bdes.ps @@ -0,0 +1,2945 @@ +%! +%%BoundingBox: (atend) +%%Pages: (atend) +%%DocumentFonts: (atend) +%%EndComments +% +% FrameMaker PostScript Prolog 2.0, for use with FrameMaker 2.0 +% Copyright (c) 1986,87,89 by Frame Technology, Inc. All rights reserved. +% +% Known Problems: +% Due to bugs in Transcript, the 'PS-Adobe-' is omitted from line 1 +/FMversion (2.0) def +% Set up Color vs. Black-and-White + /FMPrintInColor systemdict /colorimage known def +% Uncomment this line to force b&w on color printer +% /FMPrintInColor false def +/FrameDict 190 dict def +systemdict /errordict known not {/errordict 10 dict def + errordict /rangecheck {stop} put} if +% The readline in 23.0 doesn't recognize cr's as nl's on AppleTalk +FrameDict /tmprangecheck errordict /rangecheck get put +errordict /rangecheck {FrameDict /bug true put} put +FrameDict /bug false put +mark +% Some PS machines read past the CR, so keep the following 3 lines together! +currentfile 5 string readline +00 +0000000000 +cleartomark +errordict /rangecheck FrameDict /tmprangecheck get put +FrameDict /bug get { + /readline { + /gstring exch def + /gfile exch def + /gindex 0 def + { + gfile read pop + dup 10 eq {exit} if + dup 13 eq {exit} if + gstring exch gindex exch put + /gindex gindex 1 add def + } loop + pop + gstring 0 gindex getinterval true + } def + } if +/FMVERSION { + FMversion ne { + /Times-Roman findfont 18 scalefont setfont + 100 100 moveto + (FrameMaker version does not match postscript_prolog!) + dup = + show showpage + } if + } def +/FMLOCAL { + FrameDict begin + 0 def + end + } def + /gstring FMLOCAL + /gfile FMLOCAL + /gindex FMLOCAL + /orgxfer FMLOCAL + /orgproc FMLOCAL + /organgle FMLOCAL + /orgfreq FMLOCAL + /yscale FMLOCAL + /xscale FMLOCAL + /manualfeed FMLOCAL + /paperheight FMLOCAL + /paperwidth FMLOCAL +/FMDOCUMENT { + array /FMfonts exch def + /#copies exch def + FrameDict begin + 0 ne dup {setmanualfeed} if + /manualfeed exch def + /paperheight exch def + /paperwidth exch def + setpapername + manualfeed {true} {papersize} ifelse + {manualpapersize} {false} ifelse + {desperatepapersize} if + /yscale exch def + /xscale exch def + currenttransfer cvlit /orgxfer exch def + currentscreen cvlit /orgproc exch def + /organgle exch def /orgfreq exch def + end + } def + /pagesave FMLOCAL + /orgmatrix FMLOCAL + /landscape FMLOCAL +/FMBEGINPAGE { + FrameDict begin + /pagesave save def + 3.86 setmiterlimit + /landscape exch 0 ne def + landscape { + 90 rotate 0 exch neg translate pop + } + {pop pop} + ifelse + xscale yscale scale + /orgmatrix matrix def + gsave + } def +/FMENDPAGE { + grestore + pagesave restore + end + showpage + } def +/FMDEFINEFONT { + FrameDict begin + findfont + ReEncode + 2 index exch + definefont exch + scalefont + FMfonts 3 1 roll + put + end + } bind def +/FMNORMALIZEGRAPHICS { + newpath + 0.0 0.0 moveto + 1 setlinewidth + 0 setlinecap + 0 0 0 sethsbcolor + 0 setgray + } bind def + /fx FMLOCAL + /fy FMLOCAL + /fh FMLOCAL + /fw FMLOCAL + /llx FMLOCAL + /lly FMLOCAL + /urx FMLOCAL + /ury FMLOCAL +/FMBEGINEPSF { + end + /FMEPSF save def + /showpage {} def + FMNORMALIZEGRAPHICS + [/fy /fx /fh /fw /ury /urx /lly /llx] {exch def} forall + fx fy translate + rotate + fw urx llx sub div fh ury lly sub div scale + llx neg lly neg translate + } bind def +/FMENDEPSF { + FMEPSF restore + FrameDict begin + } bind def +FrameDict begin +/setmanualfeed { +%%BeginFeature *ManualFeed True + statusdict /manualfeed true put +%%EndFeature + } def +/max {2 copy lt {exch} if pop} bind def +/min {2 copy gt {exch} if pop} bind def +/inch {72 mul} def +/pagedimen { + paperheight sub abs 16 lt exch + paperwidth sub abs 16 lt and + {/papername exch def} {pop} ifelse + } def + /papersizedict FMLOCAL +/setpapername { + /papersizedict 14 dict def + papersizedict begin + /papername /unknown def + /Letter 8.5 inch 11.0 inch pagedimen + /LetterSmall 7.68 inch 10.16 inch pagedimen + /Tabloid 11.0 inch 17.0 inch pagedimen + /Ledger 17.0 inch 11.0 inch pagedimen + /Legal 8.5 inch 14.0 inch pagedimen + /Statement 5.5 inch 8.5 inch pagedimen + /Executive 7.5 inch 10.0 inch pagedimen + /A3 11.69 inch 16.5 inch pagedimen + /A4 8.26 inch 11.69 inch pagedimen + /A4Small 7.47 inch 10.85 inch pagedimen + /B4 10.125 inch 14.33 inch pagedimen + /B5 7.16 inch 10.125 inch pagedimen + end + } def +/papersize { + papersizedict begin + /Letter {lettertray} def + /LetterSmall {lettertray lettersmall} def + /Tabloid {11x17tray} def + /Ledger {ledgertray} def + /Legal {legaltray} def + /Statement {statementtray} def + /Executive {executivetray} def + /A3 {a3tray} def + /A4 {a4tray} def + /A4Small {a4tray a4small} def + /B4 {b4tray} def + /B5 {b5tray} def + /unknown {unknown} def + papersizedict dup papername known {papername} {/unknown} ifelse get + end + /FMdicttop countdictstack 1 add def + statusdict begin stopped end + countdictstack -1 FMdicttop {pop end} for + } def +/manualpapersize { + papersizedict begin + /Letter {letter} def + /LetterSmall {lettersmall} def + /Tabloid {11x17} def + /Ledger {ledger} def + /Legal {legal} def + /Statement {statement} def + /Executive {executive} def + /A3 {a3} def + /A4 {a4} def + /A4Small {a4small} def + /B4 {b4} def + /B5 {b5} def + /unknown {unknown} def + papersizedict dup papername known {papername} {/unknown} ifelse get + end + stopped + } def +/desperatepapersize { + statusdict /setpageparams known + { + paperwidth paperheight 0 1 + statusdict begin + {setpageparams} stopped pop + end + } if + } def +/savematrix { + orgmatrix currentmatrix pop + } bind def +/restorematrix { + orgmatrix setmatrix + } bind def +/dmatrix matrix def +/dpi 72 0 dmatrix defaultmatrix dtransform + dup mul exch dup mul add sqrt def +/freq dpi 18.75 div 8 div round dup 0 eq {pop 1} if 8 mul dpi exch div def +/sangle 1 0 dmatrix defaultmatrix dtransform exch atan def +/DiacriticEncoding [ +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl +/numbersign /dollar /percent /ampersand /quotesingle /parenleft +/parenright /asterisk /plus /comma /hyphen /period /slash /zero /one +/two /three /four /five /six /seven /eight /nine /colon /semicolon +/less /equal /greater /question /at /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 /bracketleft /backslash +/bracketright /asciicircum /underscore /grave /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 /braceleft /bar +/braceright /asciitilde /.notdef /Adieresis /Aring /Ccedilla /Eacute +/Ntilde /Odieresis /Udieresis /aacute /agrave /acircumflex /adieresis +/atilde /aring /ccedilla /eacute /egrave /ecircumflex /edieresis +/iacute /igrave /icircumflex /idieresis /ntilde /oacute /ograve +/ocircumflex /odieresis /otilde /uacute /ugrave /ucircumflex +/udieresis /dagger /.notdef /cent /sterling /section /bullet +/paragraph /germandbls /registered /copyright /trademark /acute +/dieresis /.notdef /AE /Oslash /.notdef /.notdef /.notdef /.notdef +/yen /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/ordfeminine /ordmasculine /.notdef /ae /oslash /questiondown +/exclamdown /logicalnot /.notdef /florin /.notdef /.notdef +/guillemotleft /guillemotright /ellipsis /.notdef /Agrave /Atilde +/Otilde /OE /oe /endash /emdash /quotedblleft /quotedblright +/quoteleft /quoteright /.notdef /.notdef /ydieresis /Ydieresis +/fraction /currency /guilsinglleft /guilsinglright /fi /fl /daggerdbl +/periodcentered /quotesinglbase /quotedblbase /perthousand +/Acircumflex /Ecircumflex /Aacute /Edieresis /Egrave /Iacute +/Icircumflex /Idieresis /Igrave /Oacute /Ocircumflex /.notdef /Ograve +/Uacute /Ucircumflex /Ugrave /dotlessi /circumflex /tilde /macron +/breve /dotaccent /ring /cedilla /hungarumlaut /ogonek /caron +] def +/ReEncode { + dup + length + dict begin + { + 1 index /FID ne + {def} + {pop pop} ifelse + } forall + Encoding StandardEncoding eq + { + /Encoding DiacriticEncoding def + }if + currentdict + end + } bind def +/graymode true def + /bwidth FMLOCAL + /bpside FMLOCAL + /bstring FMLOCAL + /onbits FMLOCAL + /offbits FMLOCAL + /xindex FMLOCAL + /yindex FMLOCAL + /x FMLOCAL + /y FMLOCAL +/setpattern { + /bwidth exch def + /bpside exch def + /bstring exch def + /onbits 0 def /offbits 0 def + freq sangle landscape {90 add} if + {/y exch def + /x exch def + /xindex x 1 add 2 div bpside mul cvi def + /yindex y 1 add 2 div bpside mul cvi def + bstring yindex bwidth mul xindex 8 idiv add get + 1 7 xindex 8 mod sub bitshift and 0 ne + {/onbits onbits 1 add def 1} + {/offbits offbits 1 add def 0} + ifelse + } + setscreen + {} settransfer + offbits offbits onbits add div FMsetgray + /graymode false def + } bind def +/grayness { + FMsetgray + graymode not { + /graymode true def + orgxfer cvx settransfer + orgfreq organgle orgproc cvx setscreen + } if + } bind def + /HUE FMLOCAL + /SAT FMLOCAL + /BRIGHT FMLOCAL + /Colors FMLOCAL +FMPrintInColor + + { + /HUE 0 def + /SAT 0 def + /BRIGHT 0 def + % array of arrays Hue and Sat values for the separations [HUE BRIGHT] + /Colors + [[0 0 ] % black + [0 0 ] % white + [0.00 1.0] % red + [0.37 1.0] % green + [0.60 1.0] % blue + [0.50 1.0] % cyan + [0.83 1.0] % magenta + [0.16 1.0] % comment / yellow + ] def + + /BEGINBITMAPCOLOR { + BITMAPCOLOR} def + /BEGINBITMAPCOLORc { + BITMAPCOLORc} def + /K { + Colors exch get dup + 0 get /HUE exch store + 1 get /BRIGHT exch store + HUE 0 eq BRIGHT 0 eq and + {1.0 SAT sub setgray} + {HUE SAT BRIGHT sethsbcolor} + ifelse + } def + /FMsetgray { + /SAT exch 1.0 exch sub store + HUE 0 eq BRIGHT 0 eq and + {1.0 SAT sub setgray} + {HUE SAT BRIGHT sethsbcolor} + ifelse + } bind def + } + + { + /BEGINBITMAPCOLOR { + BITMAPGRAY} def + /BEGINBITMAPCOLORc { + BITMAPGRAYc} def + /FMsetgray {setgray} bind def + /K { + pop + } def + } +ifelse +/normalize { + transform round exch round exch itransform + } bind def +/dnormalize { + dtransform round exch round exch idtransform + } bind def +/lnormalize { + 0 dtransform exch cvi 2 idiv 2 mul 1 add exch idtransform pop + } bind def +/H { + lnormalize setlinewidth + } bind def +/Z { + setlinecap + } bind def +/X { + fillprocs exch get exec + } bind def +/V { + gsave eofill grestore + } bind def +/N { + stroke + } bind def +/M {newpath moveto} bind def +/E {lineto} bind def +/D {curveto} bind def +/O {closepath} bind def + /n FMLOCAL +/L { + /n exch def + newpath + normalize + moveto + 2 1 n {pop normalize lineto} for + } bind def +/Y { + L + closepath + } bind def + /x1 FMLOCAL + /x2 FMLOCAL + /y1 FMLOCAL + /y2 FMLOCAL + /rad FMLOCAL +/R { + /y2 exch def + /x2 exch def + /y1 exch def + /x1 exch def + x1 y1 + x2 y1 + x2 y2 + x1 y2 + 4 Y + } bind def +/RR { + /rad exch def + normalize + /y2 exch def + /x2 exch def + normalize + /y1 exch def + /x1 exch def + newpath + x1 y1 rad add moveto + x1 y2 x2 y2 rad arcto + x2 y2 x2 y1 rad arcto + x2 y1 x1 y1 rad arcto + x1 y1 x1 y2 rad arcto + closepath + 16 {pop} repeat + } bind def +/C { + grestore + gsave + R + clip + } bind def +/U { + grestore + gsave + } bind def +/F { + FMfonts exch get + setfont + } bind def +/T { + moveto show + } bind def +/RF { + rotate + 0 ne {-1 1 scale} if + } bind def +/TF { + gsave + moveto + RF + show + grestore + } bind def +/P { + moveto + 0 32 3 2 roll widthshow + } bind def +/PF { + gsave + moveto + RF + 0 32 3 2 roll widthshow + grestore + } bind def +/S { + moveto + 0 exch ashow + } bind def +/SF { + gsave + moveto + RF + 0 exch ashow + grestore + } bind def +/B { + moveto + 0 32 4 2 roll 0 exch awidthshow + } bind def +/BF { + gsave + moveto + RF + 0 32 4 2 roll 0 exch awidthshow + grestore + } bind def + /x FMLOCAL + /y FMLOCAL + /dx FMLOCAL + /dy FMLOCAL + /dl FMLOCAL + /t FMLOCAL + /t2 FMLOCAL + /Cos FMLOCAL + /Sin FMLOCAL + /r FMLOCAL +/W { + dnormalize + /dy exch def + /dx exch def + normalize + /y exch def + /x exch def + /dl dx dx mul dy dy mul add sqrt def + dl 0.0 gt { + /t currentlinewidth def + savematrix + /Cos dx dl div def + /Sin dy dl div def + /r [Cos Sin Sin neg Cos 0.0 0.0] def + /t2 t 2.5 mul 3.5 max def + newpath + x y translate + r concat + 0.0 0.0 moveto + dl t 2.7 mul sub 0.0 rlineto + stroke + restorematrix + x dx add y dy add translate + r concat + t 0.67 mul setlinewidth + t 1.61 mul neg 0.0 translate + 0.0 0.0 moveto + t2 1.7 mul neg t2 2.0 div moveto + 0.0 0.0 lineto + t2 1.7 mul neg t2 2.0 div neg lineto + stroke + t setlinewidth + restorematrix + } if + } bind def +/G { + gsave + newpath + normalize translate 0.0 0.0 moveto + dnormalize scale + 0.0 0.0 1.0 5 3 roll arc + closepath fill + grestore + } bind def +/A { + gsave + savematrix + newpath + 2 index 2 div add exch 3 index 2 div sub exch + normalize 2 index 2 div sub exch 3 index 2 div add exch + translate + scale + 0.0 0.0 1.0 5 3 roll arc + restorematrix + stroke + grestore + } bind def + /x FMLOCAL + /y FMLOCAL + /w FMLOCAL + /h FMLOCAL + /xx FMLOCAL + /yy FMLOCAL + /ww FMLOCAL + /hh FMLOCAL + /FMsaveobject FMLOCAL + /FMoptop FMLOCAL + /FMdicttop FMLOCAL +/BEGINPRINTCODE { + /FMdicttop countdictstack 1 add def + /FMoptop count 4 sub def + /FMsaveobject save def + userdict begin + /showpage {} def + FMNORMALIZEGRAPHICS + 3 index neg 3 index neg translate + } bind def +/ENDPRINTCODE { + count -1 FMoptop {pop pop} for + countdictstack -1 FMdicttop {pop end} for + FMsaveobject restore + } bind def +/gn { + 0 + { 46 mul + cf read pop + 32 sub + dup 46 lt {exit} if + 46 sub add + } loop + add + } bind def + /str FMLOCAL +/cfs { + /str sl string def + 0 1 sl 1 sub {str exch val put} for + str def + } bind def +/ic [ + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0223 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0223 + 0 + {0 hx} {1 hx} {2 hx} {3 hx} {4 hx} {5 hx} {6 hx} {7 hx} {8 hx} {9 hx} + {10 hx} {11 hx} {12 hx} {13 hx} {14 hx} {15 hx} {16 hx} {17 hx} {18 hx} + {19 hx} {gn hx} {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} + {13} {14} {15} {16} {17} {18} {19} {gn} {0 wh} {1 wh} {2 wh} {3 wh} + {4 wh} {5 wh} {6 wh} {7 wh} {8 wh} {9 wh} {10 wh} {11 wh} {12 wh} + {13 wh} {14 wh} {gn wh} {0 bl} {1 bl} {2 bl} {3 bl} {4 bl} {5 bl} {6 bl} + {7 bl} {8 bl} {9 bl} {10 bl} {11 bl} {12 bl} {13 bl} {14 bl} {gn bl} + {0 fl} {1 fl} {2 fl} {3 fl} {4 fl} {5 fl} {6 fl} {7 fl} {8 fl} {9 fl} + {10 fl} {11 fl} {12 fl} {13 fl} {14 fl} {gn fl} + ] def + /sl FMLOCAL + /val FMLOCAL + /ws FMLOCAL + /im FMLOCAL + /bs FMLOCAL + /cs FMLOCAL + /len FMLOCAL + /pos FMLOCAL +/ms { + /sl exch def + /val 255 def + /ws cfs + /im cfs + /val 0 def + /bs cfs + /cs cfs + } bind def +400 ms +/ip { + is + 0 + cf cs readline pop + { ic exch get exec + add + } forall + pop + + } bind def +/wh { + /len exch def + /pos exch def + ws 0 len getinterval im pos len getinterval copy pop + pos len + } bind def +/bl { + /len exch def + /pos exch def + bs 0 len getinterval im pos len getinterval copy pop + pos len + } bind def +/s1 1 string def +/fl { + /len exch def + /pos exch def + /val cf s1 readhexstring pop 0 get def + pos 1 pos len add 1 sub {im exch val put} for + pos len + } bind def +/hx { + 3 copy getinterval + cf exch readhexstring pop pop + } bind def + /h FMLOCAL + /w FMLOCAL + /d FMLOCAL + /lb FMLOCAL + /bitmapsave FMLOCAL + /is FMLOCAL + /cf FMLOCAL +/wbytes { + dup + 8 eq {pop} {1 eq {7 add 8 idiv} {3 add 4 idiv} ifelse} ifelse + } bind def +/BEGINBITMAPBWc { + 1 {} COMMONBITMAPc + } bind def +/BEGINBITMAPGRAYc { + 8 {} COMMONBITMAPc + } bind def +/BEGINBITMAP2BITc { + 2 {} COMMONBITMAPc + } bind def +/COMMONBITMAPc { + /r exch def + /d exch def + gsave + translate rotate scale /h exch def /w exch def + /lb w d wbytes def + sl lb lt {lb ms} if + /bitmapsave save def + r + /is im 0 lb getinterval def + ws 0 lb getinterval is copy pop + /cf currentfile def + w h d [w 0 0 h neg 0 h] + {ip} image + bitmapsave restore + grestore + } bind def +/BEGINBITMAPBW { + 1 {} COMMONBITMAP + } bind def +/BEGINBITMAPGRAY { + 8 {} COMMONBITMAP + } bind def +/BEGINBITMAP2BIT { + 2 {} COMMONBITMAP + } bind def +/COMMONBITMAP { + /r exch def + /d exch def + gsave + translate rotate scale /h exch def /w exch def + /bitmapsave save def + r + /is w d wbytes string def + /cf currentfile def + w h d [w 0 0 h neg 0 h] + {cf is readhexstring pop} image + bitmapsave restore + grestore + } bind def + /proc1 FMLOCAL + /proc2 FMLOCAL + /newproc FMLOCAL +/Fmcc { + /proc2 exch cvlit def + /proc1 exch cvlit def + /newproc proc1 length proc2 length add array def + newproc 0 proc1 putinterval + newproc proc1 length proc2 putinterval + newproc cvx +} bind def +/ngrayt 256 array def +/nredt 256 array def +/nbluet 256 array def +/ngreent 256 array def + /gryt FMLOCAL + /blut FMLOCAL + /grnt FMLOCAL + /redt FMLOCAL + /indx FMLOCAL + /cynu FMLOCAL + /magu FMLOCAL + /yelu FMLOCAL + /k FMLOCAL + /u FMLOCAL +/colorsetup { + currentcolortransfer + /gryt exch def + /blut exch def + /grnt exch def + /redt exch def + 0 1 255 { + /indx exch def + /cynu 1 red indx get 255 div sub def + /magu 1 green indx get 255 div sub def + /yelu 1 blue indx get 255 div sub def + /k cynu magu min yelu min def + /u k currentundercolorremoval exec def + nredt indx 1 0 cynu u sub max sub redt exec put + ngreent indx 1 0 magu u sub max sub grnt exec put + nbluet indx 1 0 yelu u sub max sub blut exec put + ngrayt indx 1 k currentblackgeneration exec sub gryt exec put + } for + {255 mul cvi nredt exch get} + {255 mul cvi ngreent exch get} + {255 mul cvi nbluet exch get} + {255 mul cvi ngrayt exch get} + setcolortransfer + {pop 0} setundercolorremoval + {} setblackgeneration + } bind def + /tran FMLOCAL +/fakecolorsetup { + /tran 256 string def + 0 1 255 {/indx exch def + tran indx + red indx get 77 mul + green indx get 151 mul + blue indx get 28 mul + add add 256 idiv put} for + currenttransfer + {255 mul cvi tran exch get 255.0 div} + exch Fmcc settransfer +} bind def +/BITMAPCOLOR { + /d 8 def + gsave + translate rotate scale /h exch def /w exch def + /bitmapsave save def + colorsetup + /is w d wbytes string def + /cf currentfile def + w h d [w 0 0 h neg 0 h] + {cf is readhexstring pop} {is} {is} true 3 colorimage + bitmapsave restore + grestore + } bind def +/BITMAPCOLORc { + /d 8 def + gsave + translate rotate scale /h exch def /w exch def + /lb w d wbytes def + sl lb lt {lb ms} if + /bitmapsave save def + colorsetup + /is im 0 lb getinterval def + ws 0 lb getinterval is copy pop + /cf currentfile def + w h d [w 0 0 h neg 0 h] + {ip} {is} {is} true 3 colorimage + bitmapsave restore + grestore + } bind def +/BITMAPGRAY { + 8 {fakecolorsetup} COMMONBITMAP + } bind def +/BITMAPGRAYc { + 8 {fakecolorsetup} COMMONBITMAPc + } bind def +/ENDBITMAP { + } bind def +end +%%EndProlog +%%BeginSetup +(2.0) FMVERSION +1 1 612 792 0 1 16 FMDOCUMENT +/fillprocs 32 array def +fillprocs 0 { 0.000000 grayness } put +fillprocs 1 { 0.100000 grayness } put +fillprocs 2 { 0.300000 grayness } put +fillprocs 3 { 0.500000 grayness } put +fillprocs 4 { 0.700000 grayness } put +fillprocs 5 { 0.900000 grayness } put +fillprocs 6 { 0.970000 grayness } put +fillprocs 7 { 1.000000 grayness } put +fillprocs 8 {<0f87c3e1f0783c1e> 8 1 setpattern } put +fillprocs 9 {<0f1e3c78f0e1c387> 8 1 setpattern } put +fillprocs 10 { 8 1 setpattern } put +fillprocs 11 { 8 1 setpattern } put +fillprocs 12 {<8142241818244281> 8 1 setpattern } put +fillprocs 13 {<8040201008040201> 8 1 setpattern } put +fillprocs 14 {<03060c183060c081> 8 1 setpattern } put +fillprocs 15 {} put +fillprocs 16 { 1.000000 grayness } put +fillprocs 17 { 0.900000 grayness } put +fillprocs 18 { 0.700000 grayness } put +fillprocs 19 { 0.500000 grayness } put +fillprocs 20 { 0.300000 grayness } put +fillprocs 21 { 0.100000 grayness } put +fillprocs 22 { 0.030000 grayness } put +fillprocs 23 { 0.000000 grayness } put +fillprocs 24 { 8 1 setpattern } put +fillprocs 25 { 8 1 setpattern } put +fillprocs 26 {<3333333333333333> 8 1 setpattern } put +fillprocs 27 {<0000ffff0000ffff> 8 1 setpattern } put +fillprocs 28 {<7ebddbe7e7dbbd7e> 8 1 setpattern } put +fillprocs 29 {<7fbfdfeff7fbfdfe> 8 1 setpattern } put +fillprocs 30 { 8 1 setpattern } put +fillprocs 31 {} put +%%EndSetup +0 12 /Helvetica-Bold FMDEFINEFONT +1 12 /Helvetica-BoldOblique FMDEFINEFONT +%%Page: "-1" 1 +%%BeginPaperSize: Letter +%%EndPaperSize +612 792 0 FMBEGINPAGE +144 144 468 396 R +7 X +0 K +V +0 F +0 X +1.2 (IMPLEMENT) 178.34 388 S +1.2 (A) 258.88 388 S +1.2 (TION NOTES ON ) 267.85 388 S +1 F +1.2 (bdes) 382.61 388 S +0 F +1.2 (\0501\051) 415.4 388 S +1.2 (Matt Bishop) 265.09 338 S +1.2 (T) 197.74 288 S +1.2 (echnical Report PCS-TR91-158) 205.38 288 S +FMENDPAGE +%%EndPage: "-1" 2 +%%Page: "0" 2 +612 792 0 FMBEGINPAGE +72 72 540 720 R +7 X +0 K +V +FMENDPAGE +%%EndPage: "0" 3 +0 12 /Times-Roman FMDEFINEFONT +1 18 /Times-Bold FMDEFINEFONT +2 18 /Times-BoldItalic FMDEFINEFONT +3 12 /Times-Italic FMDEFINEFONT +4 12 /Times-Bold FMDEFINEFONT +5 10 /Times-Roman FMDEFINEFONT +6 12 /Courier FMDEFINEFONT +7 12 /Courier-Oblique FMDEFINEFONT +8 12 /ZapfDingbats FMDEFINEFONT +9 12 /Symbol FMDEFINEFONT +10 12 /Courier-Bold FMDEFINEFONT +%%Page: "1" 3 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 1 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +1 F +0 X +(Implementation Notes on ) 179.84 708 T +2 F +(bdes) 378.21 708 T +1 F +(\0501\051) 411.19 708 T +0 F +( ) 432.17 708 T +3 F +(Matt Bishop) 276.51 676 T +0 F +(Department of Mathematics and Computer Science) 182.92 656 T +(Dartmouth College) 259.86 642 T +(Hanover) 257.45 628 T +(, NH 03755) 298.26 628 T +3 F +(ABSTRACT) 277.68 602 T +0 F +0.27 (This note describes the implementation of ) 108 582 P +3 F +0.27 (bdes) 314.13 582 P +0 F +0.27 (, the \336le encryption program being) 336.12 582 P +0.36 (distributed in the 4.4 release of the Berkeley Software Distribution. It implements) 108 568 P +(all modes of the Data Encryption Standard program.) 108 554 T +4 F +(1. Intr) 72 528 T +(oduction) 104.43 528 T +0 F +-0.09 (The Data Encryption Standard is a standard endorsed by the federal government. It is con-) 108 504 P +-0.56 (siderably stronger than the algorithm used by the ) 72 484 P +5 F +-0.47 (UNIX) 305.36 484 P +0 F +-0.56 (\252 ) 330.34 484 P +3 F +-0.56 (crypt) 344.53 484 P +0 F +-0.56 (\0501\051 program, and therefore is a more) 369.18 484 P +0.11 (suitable candidate for protecting information, especially information contained in ) 72 464 P +5 F +0.09 (ASCII) 466.05 464 P +0 F +0.11 ( \336les. The) 492.14 464 P +-0.65 (program ) 72 444 P +3 F +-0.65 (bdes) 114.99 444 P +0 F +-0.65 (\0501\051 implements the DES and all of its modes, including the two authentication modes.) 136.97 444 P +-0.59 (Because others may wish to write software compatible with this program, this note presents) 108 420 P +-0.04 (the layout of the encrypted \336les produced by ) 72 400 P +3 F +-0.04 (bdes) 288.86 400 P +0 F +-0.04 ( as well as internal details relevant to the imple-) 310.85 400 P +-0.15 (mentation. Whereever possible and appropriate, the description of the ) 72 380 P +3 F +-0.15 (des) 408.04 380 P +0 F +-0.15 (\0501\051 program given in [4]) 424.03 380 P +-0.2 (has been followed; thus, ) 72 360 P +3 F +-0.2 (bdes) 190.77 360 P +0 F +-0.2 ( is completely compatible with that program. However) 212.75 360 P +-0.2 (, ) 473.33 360 P +3 F +-0.2 (bdes) 479.12 360 P +0 F +-0.2 ( also of-) 501.11 360 P +(fers several extensions to ) 72 340 T +3 F +(des) 195.9 340 T +0 F +( that are not compatible, and these will be explicitly pointed out.) 211.89 340 T +-0.14 (In this note, strings typed as shown will be in ) 108 316 P +6 F +-0.34 (Courier Roman font) 326.78 316 P +0 F +-0.14 (, and strings to be) 455.62 316 P +-0.42 (chosen by the user will be in ) 72 296 P +7 F +-1 (Courier Oblique font) 209.32 296 P +0 F +-0.42 (. The space character \050) 351.24 296 P +5 F +-0.35 (ASCII) 457.79 296 P +0 F +-0.42 ( <) 483.88 296 P +5 F +-0.35 (SP) 493.23 296 P +0 F +-0.42 (>, octal) 504.34 296 P +-0.43 (40, decimal 32, hex 20\051 will be represented as \322) 72 276 P +8 F +-0.47 (z) 296.98 276 P +0 F +-0.43 (\323 and the newline character \050) 301.96 276 P +5 F +-0.35 (ASCII) 438.03 276 P +0 F +-0.43 ( <) 464.13 276 P +5 F +-0.35 (NL) 473.46 276 P +0 F +-0.43 (>, octal 12,) 486.79 276 P +-0.05 (decimal 10, hex a\051 as \322) 72 256 P +9 F +-0.05 (\277) 181.65 256 P +0 F +-0.05 (\323. Because it is often more convenient to represent arbitrary characters as) 189.54 256 P +1.13 (a sequence of hexadecimal digits, that representation will often be used; these digits will be in) 72 236 P +10 F +(Courier Bold font) 72 216 T +0 F +( with spaces often inserted for readability) 194.33 216 T +(.) 392.07 216 T +4 F +(2. Overview and Use) 72 184 T +3 F +-0.39 (Bdes) 108 160 P +0 F +-0.39 ( implements the Data Encryption Standard algorithm in software, and enables the user) 131.32 160 P +-0.61 (to encrypt data using any of the four modes of operation of the DES \050Electronic Code Book, Cipher) 72 140 P +72 72 540 720 C +72 72 540 117 C +72 72 549 108 R +7 X +0 K +V +5 F +0 X +(This work is based on work funded by grant NAG2-680 from the National +Aeronautics and Space Administration to ) 72 101.33 T +(Dartmouth College.) 72 89.33 T +(UNIX is a Registered T) 72 77.33 T +(rademark of A) 166.58 77.33 T +(T&T Bell Laboratories.) 223.75 77.33 T +72 72 540 720 C +0 0 612 792 C +72 126 225 126 2 L +7 X +0 K +V +0.5 H +2 Z +0 X +N +FMENDPAGE +%%EndPage: "1" 4 +%%Page: "2" 4 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 2 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +0.31 (Block Chaining, ) 72 712 P +3 F +0.31 (k) 154.25 712 P +0 F +0.31 (-bit Cipher Feed Back, and ) 159.58 712 P +3 F +0.31 (k) 293.71 712 P +0 F +0.31 (-bit Output Feed Back\051 as well as the Alternate ) 299.04 712 P +3 F +0.31 (k) 530.68 712 P +0 F +0.31 (-) 536.01 712 P +-0.04 (bit Cipher Feed Back mode. Further) 72 692 P +-0.04 (, ) 244.52 692 P +3 F +-0.04 (bdes) 250.48 692 P +0 F +-0.04 ( supports message authentication code generation based) 272.46 692 P +(on both the Cipher Block Chaining mode and the ) 72 672 T +3 F +(k) 310.86 672 T +0 F +(-bit Cipher Feed Back mode.) 316.19 672 T +0.07 (By default, ) 108 648 P +3 F +0.07 (bdes) 164.43 648 P +0 F +0.07 ( encrypts an input \336le using Cipher Block Chaining mode, and is invoked) 186.41 648 P +-0.4 (as a \336lter) 72 628 P +-0.4 (. The key may be speci\336ed either on the command line or may be typed to the prompt. So,) 114.51 628 P +(if the input \336le ) 72 608 T +7 F +(inputf) 145.96 608 T +(ile) 189.14 608 T +0 F +( contains the message) 210.73 608 T +6 F +(a) 253.9 584 T +8 F +(z) 261.1 584 T +6 F +(test) 266.07 584 T +8 F +(z) 294.86 584 T +6 F +(message) 299.83 584 T +9 F +(\277) 350.21 584 T +0 F +(then the following command encrypts it using the key ) 72 560 T +6 F +(abcdefgh) 333.5 560 T +0 F +(:) 391.07 560 T +6 F +(bdes -k abcdefgh < ) 158.48 536 T +7 F +(inputf) 295.21 536 T +(ile) 338.38 536 T +6 F +( > ) 359.97 536 T +7 F +(outputf) 381.56 536 T +(ile) 431.93 536 T +0 F +(The option ) 72 512 T +4 F +(-k) 127.3 512 T +0 F +( indicates the next ar) 137.96 512 T +(gument is the key) 237.01 512 T +(. Now ) 321.17 512 T +7 F +(outputf) 353.48 512 T +(ile) 403.86 512 T +0 F +( contains) 425.45 512 T +10 F +(16 0e eb af 68 a0 d0 19 f1 a2 9b 31 0d 8a 01 c3) 136.89 488 T +0 F +0.06 (Other modes are speci\336ed using command-line options, as is control of the way the key is) 108 464 P +(interpreted. The next sections contain several examples, and the Appendix has the manual page.) 72 444 T +4 F +(3. Keys and Parity) 72 412 T +0 F +0.58 (The key consists of 64 bits, and may be presented in any of hex, binary) 108 388 P +0.58 (, or as a string of) 456.48 388 P +5 F +0.12 (ASCII) 72 368 P +0 F +0.14 ( characters. If the key is given in hex or binary) 98.1 368 P +0.14 (, it is used as is with no changes. However) 322.21 368 P +0.14 (, if) 526.53 368 P +-0.27 (the key is given in ) 72 348 P +5 F +-0.23 (ASCII) 161.59 348 P +0 F +-0.27 (, a delicate problem arises: by convention, the parity bit is usually set to 0.) 187.69 348 P +-0.47 (This high-order bit is generally ignored by applications; but the DES +does not do so. Instead, it dis-) 72 328 P +-0.14 (cards the low-order bit, ef) 72 308 P +-0.14 (fectively reducing the size of the space of possible keys from 2) 195.44 308 P +5 F +-0.12 (56) 495.97 312.8 P +0 F +-0.14 ( to 2) 505.97 308 P +5 F +-0.12 (48) 527.01 312.8 P +0 F +-0.14 (.) 537 308 P +-0.46 ( T) 108 284 P +-0.46 (o preserve the size of the key space, the value of the parity bit must be related to the value) 117.03 284 P +-0.09 (in the low-order bit, so the program sets the high-order bit to make each character in the key be of) 72 264 P +-0.7 (odd parity) 72 244 P +-0.7 (. \050Note that the initial value of the parity bit is ) 119.49 244 P +3 F +-0.7 (not) 334.99 244 P +0 F +-0.7 ( used in this computation.\051 For example,) 350.31 244 P +(if the key is ) 72 224 T +6 F +(abcdefgh) 131.29 224 T +0 F +(, the actual key bits used are determined as follows:) 188.86 224 T +5 F +(ASCII) 99 200 T +0 F +( key) 125.1 200 T +6 F +(a) 243 200 T +(b) 279 200 T +(c) 315 200 T +(d) 351 200 T +(e) 387 200 T +(f) 423 200 T +(g) 459 200 T +(h) 495 200 T +5 F +(ASCII) 99 180 T +0 F +( key bits \050hex\051) 125.1 180 T +10 F +(61) 243 180 T +(62) 279 180 T +(63) 315 180 T +(64) 351 180 T +(65) 387 180 T +(66) 423 180 T +(67) 459 180 T +(68) 495 180 T +0 F +(parity) 99 160 T +(odd) 243 160 T +(odd) 279 160 T +(even) 315 160 T +(odd) 351 160 T +(even) 387 160 T +(even) 423 160 T +(odd) 459 160 T +(odd) 495 160 T +(key bits used \050hex\051) 99 140 T +10 F +(61) 243 140 T +(62) 279 140 T +(e3) 315 140 T +(64) 351 140 T +(e5) 387 140 T +(e6) 423 140 T +(67) 459 140 T +(68) 495 140 T +0 F +0.18 (This convention \050as opposed to requiring even parity) 108 120 P +0.18 (, or simply copying the low-order bit) 362 120 P +-0.41 (to the high-order bit\051 was chosen to provide compatibility with the encryption program ) 72 100 P +3 F +-0.41 (des) 486.77 100 P +0 F +-0.41 ( distrib-) 502.76 100 P +-0.52 (uted by Sun Microsystems, Inc. [4]. Whether the key is entered on the command line or on the key-) 72 80 P +FMENDPAGE +%%EndPage: "2" 5 +%%Page: "3" 5 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 3 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +1.89 (board, by default it is processed into the same key schedule generated by Sun\325) 72 712 P +1.89 (s ) 471.02 712 P +3 F +1.89 (des) 480.58 712 P +0 F +1.89 (, so \336les) 496.56 712 P +(encrypted on a Sun can be decrypted using ) 72 692 T +3 F +(bdes) 280.51 692 T +0 F +( \050and vice versa\051.) 302.49 692 T +-0.3 (If the user does not wish to use the Sun convention, the option \320) 108 668 P +4 F +-0.3 (p) 411.9 668 P +0 F +-0.3 ( will disable the parity bit) 418.57 668 P +-0.62 (changing; with it, the parity bit is that of the character typed. This +is useful when the key is a known) 72 648 P +5 F +(ASCII) 72 628 T +0 F +( string and the \336le was encrypted on a system which does not alter parity bits.) 98.1 628 T +-0.24 (A key may be represented as a bit vector) 108 604 P +-0.24 (, rather than an ) 300.74 604 P +5 F +-0.2 (ASCII) 374.7 604 P +0 F +-0.24 ( string, in one of two ways. It) 400.8 604 P +0.19 (may be represented as a string of up to 16 hexadecimal digits; if fewer than 16 are given, the key) 72 584 P +0.16 (is right \336lled with 0 bits. Or) 72 564 P +0.16 (, it may be represented as a string of up to 64 binary digits, and again) 206.11 564 P +0.15 (if fewer than 64 are given, the key is right-\336lled with 0 bits. Bit +vector keys must be given on the) 72 544 P +0.51 (command line, and must begin with the characters ) 72 524 P +6 F +1.24 (0x) 320.28 524 P +0 F +0.51 ( or ) 334.67 524 P +6 F +1.24 (0X) 351.69 524 P +0 F +0.51 ( \050for hexadecimal\051 or ) 366.08 524 P +6 F +1.24 (0b) 472.71 524 P +0 F +0.51 ( or ) 487.1 524 P +6 F +1.24 (0B) 504.12 524 P +0 F +0.51 ( \050for) 518.51 524 P +(binary\051. For example, all of the following strings generate the same key schedule:) 72 504 T +5 F +(ASCII) 72 480 T +0 F +( key) 98.1 480 T +6 F +(abcdefgh) 180 480 T +0 F +(hexadecimal key) 72 460 T +6 F +(0x6162e364e5e66768) 180 460 T +0 F +(binary key) 72 440 T +6 F +(0b0110000101100010111000110110100011100101111000-) 180 440 T +(1100110011101101000) 180 420 T +0 F +-0.14 ( Note that giving the key on the command line as ) 108 396 P +6 F +-0.34 (0x6162636465666768) 345.27 396 P +0 F +-0.14 ( will ) 474.8 396 P +3 F +-0.14 (not) 499.17 396 P +0 F +-0.14 ( reset) 514.5 396 P +0.25 (the parity bits, because it is interpreted as a sequence of hex digits, not ) 72 376 P +5 F +0.21 (ASCII) 416.58 376 P +0 F +0.25 ( characters. The dif-) 442.68 376 P +0.69 (ference in interpretation is that here the user can specify all bits of the key exactly) 72 356 P +0.69 (, whereas \050on) 474.34 356 P +0.25 (most terminals\051 it is not possible to control how the parity bit of ) 72 336 P +5 F +0.21 (ASCII) 384.76 336 P +0 F +0.25 ( characters is set. On some) 410.85 336 P +0.36 (systems, it is possible to use a \322Meta\323 key to set the parity bit for an ) 72 316 P +5 F +0.3 (ASCII) 407.23 316 P +0 F +0.36 ( character; should this) 433.33 316 P +-0.3 (be the case and the user desire ) 72 296 P +3 F +-0.3 (bdes) 218.09 296 P +0 F +-0.3 ( not to reset the parity bit, the option ) 240.07 296 P +4 F +-0.3 (\320p) 415.25 296 P +0 F +-0.3 ( will force the parity bit) 427.92 296 P +(to be used as typed.) 72 276 T +4 F +(4. Encryption Output Repr) 72 244 T +(esentation) 211.05 244 T +0 F +0.01 (All modes of the DES output ciphertext in blocks; the size of the block is 64 bits \0508 bytes\051) 108 220 P +-0.25 (for ECB and CBC modes, and ) 72 200 P +3 F +-0.25 (k) 218.74 200 P +0 F +-0.25 ( bits for the ) 224.07 200 P +3 F +-0.25 (k) 281.02 200 P +0 F +-0.25 (-bit CFB and OFB modes, and there are as many out-) 286.35 200 P +-0.5 (put blocks as input blocks. However) 72 180 P +-0.5 (, as the length of the input is usually not a multiple of the block) 243.55 180 P +-0.35 (size, some padding is necessary; but as padding must be done by appending characters, these char-) 72 160 P +0.29 (acters must be distinguished from the input characters somehow) 72 140 P +0.29 (. The mechanism used is that the) 381.35 140 P +0.31 (last character of the \050decrypted\051 last block is the +\050integer\051 number of characters from the input in) 72 120 P +(the last block.) 72 100 T +FMENDPAGE +%%EndPage: "3" 6 +%%Page: "4" 6 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 4 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +-0.59 (For example, suppose ) 108 712 P +7 F +-1.41 (inputf) 214.16 712 P +-1.41 (ile) 257.34 712 P +0 F +-0.59 ( contains \322) 278.93 712 P +6 F +-1.41 (This) 329.04 712 P +8 F +-0.65 (z) 357.83 712 P +6 F +-1.41 (is) 362.8 712 P +8 F +-0.65 (z) 377.2 712 P +6 F +-1.41 (a) 382.17 712 P +8 F +-0.65 (z) 389.37 712 P +6 F +-1.41 (test) 394.35 712 P +9 F +-0.59 (\277) 423.13 712 P +0 F +-0.59 (\323, and it is encrypted in) 431.02 712 P +(CBC mode using the key \322) 72 692 T +6 F +(abcdef#@) 200.93 692 T +0 F +(\323 and the initialization vector ) 258.5 692 T +6 F +(0x0) 401.4 692 T +0 F +(; the command is) 422.99 692 T +6 F +(bdes -k abcdef#@ < ) 158.48 668 T +7 F +(inputf) 295.21 668 T +(ile) 338.38 668 T +6 F +( > ) 359.97 668 T +7 F +(outputf) 381.56 668 T +(ile) 431.93 668 T +0 F +(as CBC is the default encryption mode and ) 72 644 T +6 F +(0x0) 281.2 644 T +0 F +( the default initialization vector:) 302.79 644 T +(text) 72 620 T +6 F +(T) 117 620 T +(h) 144 620 T +(i) 171 620 T +(s) 198 620 T +8 F +(z) 225 620 T +6 F +(i) 252 620 T +(s) 279 620 T +8 F +(z) 306 620 T +6 F +(a) 333 620 T +8 F +(z) 360 620 T +6 F +(t) 387 620 T +(e) 414 620 T +(s) 441 620 T +(t) 468 620 T +9 F +(\277) 495 620 T +0 F +(hex) 72 600 T +10 F +(54) 117 600 T +(68) 144 600 T +(69) 171 600 T +(73) 198 600 T +(20) 225 600 T +(69) 252 600 T +(73) 279 600 T +(20) 306 600 T +(61) 333 600 T +(20) 360 600 T +(74) 387 600 T +(65) 414 600 T +(73) 441 600 T +(74) 468 600 T +(0a) 495 600 T +0 F +(input) 72 580 T +10 F +(54) 117 580 T +(68) 144 580 T +(69) 171 580 T +(73) 198 580 T +(20) 225 580 T +(69) 252 580 T +(73) 279 580 T +(20) 306 580 T +(61) 333 580 T +(20) 360 580 T +(74) 387 580 T +(65) 414 580 T +(73) 441 580 T +(74) 468 580 T +(0a) 495 580 T +(07) 522 580 T +0 F +(output) 72 560 T +10 F +(a5) 117 560 T +(5f) 144 560 T +(81) 171 560 T +(53) 198 560 T +(51) 225 560 T +(98) 252 560 T +(47) 279 560 T +(02) 306 560 T +(db) 333 560 T +(5a) 360 560 T +(c5) 387 560 T +(fe) 414 560 T +(50) 441 560 T +(3d) 468 560 T +(40) 495 560 T +(ce) 522 560 T +0 F +0.04 (Notice that the text is 15 characters long, so there are 7 bytes following the last full block.) 108 540 P +3 F +0.22 (Bdes) 72 520 P +0 F +0.22 ( pads this to a full block by appending one byte containing the ) 95.32 520 P +5 F +0.19 (ASCII) 399.67 520 P +0 F +0.22 ( character with numeric) 425.77 520 P +(value 7 \050the ) 72 500 T +5 F +(ASCII) 131.62 500 T +0 F +( character <) 157.71 500 T +5 F +(BEL) 214.42 500 T +0 F +(>\051. The result is then encrypted.) 233.3 500 T +0.44 (As another example, suppose ) 108 476 P +7 F +1.07 (inputf) 253.34 476 P +1.07 (ile) 296.52 476 P +0 F +0.44 ( contains \322) 318.11 476 P +6 F +1.07 (test) 370.29 476 P +0 F +0.44 (\323, and it is encrypted in ECB) 399.08 476 P +(mode using the key \322) 72 456 T +6 F +(abcdef#@) 173.93 456 T +0 F +(\323; the command is) 231.5 456 T +6 F +(bdes -b \320k abcdef#@ < ) 147.69 432 T +7 F +(inputf) 306 432 T +(ile) 349.18 432 T +6 F +( > ) 370.76 432 T +7 F +(outputf) 392.35 432 T +(ile) 442.73 432 T +0 F +(because the option ) 72 408 T +4 F +(\320b) 164.26 408 T +0 F +( signi\336es ECB mode:) 176.93 408 T +(text) 72 384 T +6 F +(t) 144 384 T +(e) 171 384 T +(s) 198 384 T +(t) 225 384 T +0 F +(hex) 72 364 T +10 F +(74) 144 364 T +(65) 171 364 T +(73) 198 364 T +(74) 225 364 T +0 F +(input) 72 344 T +10 F +(74) 144 344 T +(65) 171 344 T +(73) 198 344 T +(74) 225 344 T +(00) 252 344 T +(00) 279 344 T +(00) 306 344 T +(04) 333 344 T +0 F +(output) 72 324 T +10 F +(0d) 144 324 T +(8a) 171 324 T +(6e) 198 324 T +(57) 225 324 T +(9c) 252 324 T +(8f) 279 324 T +(27) 306 324 T +(5d) 333 324 T +0 F +-0.31 (Finally) 108 304 P +-0.31 (, if the length of the message is indeed a multiple of the block size, an extra block of) 141.21 304 P +0.83 (all 0 bits is added. Suppose ) 72 284 P +7 F +1.99 (inputf) 210.57 284 P +1.99 (ile) 253.74 284 P +0 F +0.83 ( contains \322) 275.33 284 P +6 F +1.99 (test) 328.28 284 P +9 F +0.83 (\277) 357.07 284 P +0 F +0.83 (\323, and it is encrypted in 40-bit CFB) 364.96 284 P +1.51 (mode using the key \322) 72 264 P +6 F +3.62 (abcdef#@) 179.96 264 P +0 F +1.51 (\323 and the initialization vector ) 237.53 264 P +6 F +3.62 (0x0123456789abcdef) 387.97 264 P +0 F +1.51 (; the) 517.5 264 P +(command is) 72 244 T +6 F +-0.99 (bdes -f40 -v0x0123456789abcdef -kabcdef#@ < ) 72 220 P +7 F +-0.99 (inputf) 383.67 220 P +-0.99 (ile) 426.85 220 P +6 F +-0.99 ( > ) 448.43 220 P +7 F +-0.99 (outputf) 468.04 220 P +-0.99 (ile) 518.41 220 P +0 F +0.16 (because the option ) 72 196 P +4 F +0.16 (\320f40 ) 164.75 196 P +0 F +0.16 (signi\336es 40-bit CFB mode, and ) 189.89 196 P +4 F +0.16 (-v0x01234566789abcdef) 343.96 196 P +0 F +0.16 ( sets the initial-) 465.89 196 P +(ization vector \050note that spaces between the option and its ar) 72 176 T +(gument are optional\051:) 361.57 176 T +(text) 72 152 T +6 F +(t) 144 152 T +(e) 171 152 T +(s) 198 152 T +(t) 225 152 T +9 F +(\277) 252 152 T +0 F +(hex) 72 132 T +10 F +(74) 144 132 T +(65) 171 132 T +(73) 198 132 T +(74) 225 132 T +(0a) 252 132 T +0 F +(input) 72 112 T +10 F +(74) 144 112 T +(65) 171 112 T +(73) 198 112 T +(74) 225 112 T +(0a) 252 112 T +(00) 279 112 T +(00) 306 112 T +(00) 333 112 T +(00) 360 112 T +(00) 387 112 T +0 F +(output) 72 92 T +10 F +(e2) 144 92 T +(c2) 171 92 T +(69) 198 92 T +(a4) 225 92 T +(5b) 252 92 T +(3c) 279 92 T +(3d) 306 92 T +(b3) 333 92 T +(f5) 360 92 T +(3c) 387 92 T +FMENDPAGE +%%EndPage: "4" 7 +1 12 /Times-BoldItalic FMDEFINEFONT +2 14 /Symbol FMDEFINEFONT +%%Page: "5" 7 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 5 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +(Note here the block size is 40 bits \0505 bytes\051, not 64 bits \0508 bytes\051.) 108 712 T +-0.4 (This technique allows complete compatibility with Sun\325) 108 688 P +-0.4 (s ) 374.11 688 P +3 F +-0.4 (des) 381.37 688 P +0 F +-0.4 ( program. In Sun\325) 397.36 688 P +-0.4 (s implemen-) 480.77 688 P +0.02 (tation, padding is done with random bytes rather than bytes containing all zero bits. Cryptograph-) 72 668 P +0.85 (ically) 72 648 P +0.85 (, this makes no dif) 97.87 648 P +0.85 (ference, as the DES is a suf) 189.32 648 P +0.85 (\336ciently good random cipher to obscure the) 325.74 648 P +(input \050see for example [2], Chapter 6\051, and known plaintext attacks are very dif) 72 628 T +(\336cult [1].) 451.82 628 T +4 F +(5. Differ) 72 596 T +(ences Between the Standard CFB and OFB Modes and ) 114.41 596 T +1 F +(bdes) 397.26 596 T +0 F +-0.11 (The UNIX operating system treats all \336les as streams of 8-bit bytes. In order to implement) 108 572 P +-0.08 (the CFB and OFB modes properly) 72 552 P +-0.08 (, it would be necessary to read ) 235.74 552 P +3 F +-0.08 (k) 383.74 552 P +0 F +-0.08 ( bits from the \336le, where ) 389.07 552 P +3 F +-0.08 (k) 509.51 552 P +0 F +-0.08 ( is an) 514.84 552 P +0.98 (integer between 1 and 64 inclusive. However) 72 532 P +0.98 (, this would require considerable buf) 294.22 532 P +0.98 (fering and be) 474.77 532 P +0.23 (quite inef) 72 512 P +0.23 (\336cient and prohibitively slow) 117.65 512 P +0.23 (. For these reasons, the current implementation of ) 258.48 512 P +3 F +0.23 (bdes) 501.48 512 P +0 F +0.23 ( re-) 523.46 512 P +0.47 (quires that ) 72 492 P +3 F +0.47 (k) 126.23 492 P +0 F +0.47 ( be a multiple of 8, so that an integral number of bytes will always be read from the) 131.56 492 P +(\336le. Other than this change, this mode is implemented as described in [3].) 72 472 T +-0.58 (A similar observation holds for the alternate CFB mode described in [3]. Here, only the low) 108 448 P +0.23 (7 bits of each byte are signi\336cant, and hence the parameter ) 72 428 P +3 F +0.23 (k) 358.95 428 P +0 F +0.23 ( is an integer from 1 to 56 inclusive;) 364.28 428 P +(bdes requires k to be a multiple of 7. The high-order bit is retained for encryption and decryption,) 72 408 T +(but output \050whether from encryption or decryption\051 always has the high-order bit set to zero.) 72 388 T +4 F +(6. Message Authentication Code Modes) 72 356 T +0 F +0.57 (The Data Encryption Standard provides two modes of authentication, each providing be-) 108 332 P +1.27 (tween 1 and 64 bits of authentication data. In both cases an ) 72 312 P +3 F +1.27 (n) 373.32 312 P +0 F +1.27 (-bit message authentication code) 379.32 312 P +0.62 (\050MAC\051 is generated, where 1) 72 292 P +2 F +0.73 ( ) 214.71 292 P +9 F +0.62 (\243) 218.94 292 P +0 F +0.62 ( ) 225.52 292 P +3 F +0.62 (n) 229.15 292 P +0 F +0.62 ( ) 235.14 292 P +9 F +0.62 (\243) 238.76 292 P +0 F +0.62 ( 64. The \336rst is based on the CBC encryption mode, and the) 245.35 292 P +(second on CFB mode. Both work the same.) 72 272 T +0.13 (First, the \336le is padded to a multiple of the block size by appending enough zero bits. It is) 108 248 P +-0.16 (then encrypted using the standard CBC \050or CFB\051 algorithm, but +all encrypted text is discarded ex-) 72 228 P +-0.44 (cept for the last block. The ) 72 208 P +3 F +-0.44 (n) 200.9 208 P +0 F +-0.44 ( leading bits of the last block are used as the MAC. Note that the block) 206.9 208 P +(size constrains the number of bits available as the MAC.) 72 188 T +0.71 (The implementation allows the user to specify that the MAC is to be computed in either) 108 164 P +-0.01 (CBC or CFB mode, and the user can specify any number of bits from 1 to 64 inclusive. However) 72 144 P +-0.01 (,) 537 144 P +-0.11 (because the UNIX operating system can only output bits in multiples of 8, if the number of bits of) 72 124 P +-0.08 (MAC is not a multiple of 8, the MAC will be right-padded with the minimum number of zero bits) 72 104 P +-0.31 (necessary to make the MAC length be a multiple of 8. However) 72 84 P +-0.31 (, note that as the standard \050[3], Ap-) 374.6 84 P +FMENDPAGE +%%EndPage: "5" 8 +%%Page: "6" 8 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 6 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +-0.14 (pendix F\051 requires an incomplete \336nal block be right-padded with +zeroes, the technique of forcing) 72 712 P +(the last octet to contain the number of bytes in the message is ) 72 692 T +3 F +(not) 369.47 692 T +0 F +( used here.) 384.8 692 T +-0.39 (For example, suppose ) 108 668 P +7 F +-0.94 (inputf) 214.76 668 P +-0.94 (ile) 257.93 668 P +0 F +-0.39 ( contains \322) 279.52 668 P +6 F +-0.94 (This) 330.04 668 P +8 F +-0.43 (z) 358.82 668 P +6 F +-0.94 (is) 363.8 668 P +8 F +-0.43 (z) 378.19 668 P +6 F +-0.94 (a) 383.17 668 P +8 F +-0.43 (z) 390.36 668 P +6 F +-0.94 (test) 395.34 668 P +9 F +-0.39 (\277) 424.13 668 P +0 F +-0.39 (\323, and a 64-bit MAC is) 432.02 668 P +-0.73 (to be generated using CBC mode, the key \322) 72 648 P +6 F +-1.74 (abcdef#@) 274.39 648 P +0 F +-0.73 (\323 and the initialization vector ) 331.96 648 P +6 F +-1.74 (0x0) 471.23 648 P +0 F +-0.73 (; the com-) 492.82 648 P +(mand is) 72 628 T +6 F +(bdes -m 64 -k abcdef#@ < ) 136.89 604 T +7 F +(inputf) 316.79 604 T +(ile) 359.97 604 T +6 F +( > ) 381.56 604 T +7 F +(outputf) 403.15 604 T +(ile) 453.52 604 T +0 F +(as CBC is the default encryption mode and ) 72 580 T +6 F +(0x0) 281.2 580 T +0 F +( the default initialization vector:) 302.79 580 T +(text) 72 556 T +6 F +(T) 117 556 T +(h) 144 556 T +(i) 171 556 T +(s) 198 556 T +8 F +(z) 225 556 T +6 F +(i) 252 556 T +(s) 279 556 T +8 F +(z) 306 556 T +6 F +(a) 333 556 T +8 F +(z) 360 556 T +6 F +(t) 387 556 T +(e) 414 556 T +(s) 441 556 T +(t) 468 556 T +9 F +(\277) 495 556 T +0 F +(hex) 72 536 T +10 F +(54) 117 536 T +(68) 144 536 T +(69) 171 536 T +(73) 198 536 T +(20) 225 536 T +(69) 252 536 T +(73) 279 536 T +(20) 306 536 T +(61) 333 536 T +(20) 360 536 T +(74) 387 536 T +(65) 414 536 T +(73) 441 536 T +(74) 468 536 T +(0a) 495 536 T +0 F +(input) 72 516 T +10 F +(54) 117 516 T +(68) 144 516 T +(69) 171 516 T +(73) 198 516 T +(20) 225 516 T +(69) 252 516 T +(73) 279 516 T +(20) 306 516 T +(61) 333 516 T +(20) 360 516 T +(74) 387 516 T +(65) 414 516 T +(73) 441 516 T +(74) 468 516 T +(0a) 495 516 T +(00) 522 516 T +0 F +(output) 72 496 T +10 F +(43) 117 496 T +(18) 144 496 T +(de) 171 496 T +(74) 198 496 T +(24) 225 496 T +(a9) 252 496 T +(65) 279 496 T +(d1) 306 496 T +0 F +0.04 (Notice that the text is 15 characters long, so there are 7 bytes following the last full block.) 108 476 P +3 F +(Bdes) 72 456 T +0 F +( pads this to a full block by appending a zero-\336lled byte. The result is then encrypted and the) 95.32 456 T +(last block of output is used as the MAC.) 72 436 T +0.06 (As another example, suppose we used the same text, and wanted a 36-bit MAC to be gen-) 108 412 P +6.91 (erated using 40-bit CFB mode, the key \322) 72 392 P +6 F +16.58 (abcdef#@) 314.9 392 P +0 F +6.91 (\323 and the initialization vector) 372.47 392 P +6 F +(0x0123456789abcdef) 72 372 T +0 F +(; the command is) 201.53 372 T +6 F +(bdes -m 36 -f 40 -v 0x0123456789abcdef < ) 79.32 348 T +7 F +(inputf) 374.36 348 T +(ile) 417.54 348 T +6 F +( > ) 439.13 348 T +7 F +(outputf) 460.71 348 T +(ile) 511.09 348 T +0 F +-0.19 (where ) 72 324 P +4 F +-0.19 (\320m 36) 104.11 324 P +0 F +-0.19 ( is the option to generate a 36-bit MAC, ) 134.91 324 P +4 F +-0.19 (\320f 40) 327.79 324 P +0 F +-0.19 ( indicates 40-bit CFB is to be used, and) 352.58 324 P +4 F +-0.31 (\320v 0x123456789abcdef) 72 304 P +0 F +-0.31 ( sets the initialization vector) 186.62 304 P +-0.31 (. Note that, as the key is not given on the com-) 319.95 304 P +(mand line, the user will be prompted for it. It gives:) 72 284 T +(text) 72 260 T +6 F +(T) 117 260 T +(h) 144 260 T +(i) 171 260 T +(s) 198 260 T +8 F +(z) 225 260 T +6 F +(i) 252 260 T +(s) 279 260 T +8 F +(z) 306 260 T +6 F +(a) 333 260 T +8 F +(z) 360 260 T +6 F +(t) 387 260 T +(e) 414 260 T +(s) 441 260 T +(t) 468 260 T +9 F +(\277) 495 260 T +0 F +(hex) 72 240 T +10 F +(54) 117 240 T +(68) 144 240 T +(69) 171 240 T +(73) 198 240 T +(20) 225 240 T +(69) 252 240 T +(73) 279 240 T +(20) 306 240 T +(61) 333 240 T +(20) 360 240 T +(74) 387 240 T +(65) 414 240 T +(73) 441 240 T +(74) 468 240 T +(0a) 495 240 T +0 F +(input) 72 220 T +10 F +(54) 117 220 T +(68) 144 220 T +(69) 171 220 T +(73) 198 220 T +(20) 225 220 T +(69) 252 220 T +(73) 279 220 T +(20) 306 220 T +(61) 333 220 T +(20) 360 220 T +(74) 387 220 T +(65) 414 220 T +(73) 441 220 T +(74) 468 220 T +(0a) 495 220 T +0 F +(output) 72 200 T +10 F +(2b) 117 200 T +(18) 144 200 T +(68) 171 200 T +(2d) 198 200 T +(60) 225 200 T +0 F +0.19 (Note that the MAC is padded on the right by four zero bits to produce \336ve characters that) 108 180 P +(can be output.) 72 160 T +4 F +(7. Differ) 72 128 T +(ences Between ) 114.41 128 T +1 F +(bdes) 191.01 128 T +4 F +( and Sun\325) 212.99 128 T +(s DES Implementation) 261.88 128 T +0 F +0.02 (The program ) 108 104 P +3 F +0.02 (bdes) 173.33 104 P +0 F +0.02 ( is designed to be completely compatible with Sun Microsystems, Inc.\325) 195.31 104 P +0.02 (s) 535.33 104 P +0.57 (implementation of the Data Encryption Standard, called ) 72 84 P +3 F +0.57 (des) 347.14 84 P +0 F +0.57 ( and described in [4]. Thus, \336les en-) 363.13 84 P +FMENDPAGE +%%EndPage: "6" 9 +%%Page: "7" 9 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 7 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +0 X +0.44 (crypted using ) 72 712 P +3 F +0.44 (des) 140.84 712 P +0 F +0.44 ( can be decrypted using ) 156.83 712 P +3 F +0.44 (bdes) 275.29 712 P +0 F +0.44 (, and vice versa, provided modes common to both) 297.27 712 P +-0.34 (are used. However) 72 692 P +-0.34 (, ) 160.41 692 P +3 F +-0.34 (bdes) 166.06 692 P +0 F +-0.34 ( does not allow \336les to be named on the command line, nor does it support) 188.05 692 P +-0.68 (hardware devices \050and so the ) 72 672 P +4 F +-0.68 (-s) 210.83 672 P +0 F +-0.68 ( and ) 219.49 672 P +4 F +-0.68 (-f) 241.45 672 P +0 F +-0.68 ( options of Sun\325) 249.44 672 P +-0.68 (s ) 323.71 672 P +3 F +-0.68 (des) 330.7 672 P +0 F +-0.68 ( are not available\051. Further) 346.69 672 P +-0.68 (, as encryption) 471.07 672 P +-0.05 (is the default, the Sun ) 72 652 P +3 F +-0.05 (des) 179.01 652 P +0 F +-0.05 ( ) 195 652 P +4 F +-0.05 (-e) 197.95 652 P +0 F +-0.05 ( option is not recognized. As the manual page to ) 207.27 652 P +3 F +-0.05 (bdes) 441.6 652 P +0 F +-0.05 ( is in the appen-) 463.59 652 P +(dix, these dif) 72 632 T +(ferences will not be elaborated upon further) 134.08 632 T +(.) 343.24 632 T +0.44 (Sun\325) 108 608 P +0.44 (s ) 130 608 P +3 F +0.44 (des) 138.1 608 P +0 F +0.44 ( supports the use of special-purpose hardware to encrypt and decrypt. Although) 154.09 608 P +3 F +1.33 (bdes) 72 588 P +0 F +1.33 ( does not directly support the use of such hardware, it uses the library routine ) 93.98 588 P +3 F +1.33 (encrypt) 487.05 588 P +0 F +1.33 (\0503\051,) 523.02 588 P +-0.09 (which may) 72 568 P +-0.09 (. Hardware support was not included directly to support as lar) 124.1 568 P +-0.09 (ge a number of platforms) 419.11 568 P +(as possible with installers needing to know as little about the hardware as possible.) 72 548 T +-0.08 (Sun\325) 108 524 P +-0.08 (s ) 130 524 P +3 F +-0.08 (des) 137.58 524 P +0 F +-0.08 ( supports only the CBC and ECB encryption modes; ) 153.57 524 P +3 F +-0.08 (bdes) 407.07 524 P +0 F +-0.08 ( supports all modes de-) 429.05 524 P +0.26 (scribed in [3] \050although CFB and OFB are not completely supported\051 as well as both CBC-based) 72 504 P +(and CFB-based MACs.) 72 484 T +0.15 (Although input with length not a multiple of the block size is handled in the same way by) 108 460 P +-0.47 (both ) 72 440 P +3 F +-0.47 (des) 95.85 440 P +0 F +-0.47 ( and ) 111.84 440 P +3 F +-0.47 (bdes) 134.21 440 P +0 F +-0.47 (, dif) 156.19 440 P +-0.47 (ferent values of the padding bytes are used in all but the last byte of the input.) 174.82 440 P +(Where ) 72 420 T +3 F +(bdes) 106.96 420 T +0 F +( puts zero bytes, ) 128.94 420 T +3 F +(des) 209.89 420 T +0 F +( puts bytes containing random values. The reason for Sun\325) 225.87 420 T +(s doing) 505.02 420 T +0.47 (so is to prevent a known plaintext attack on the \336le should an +attacker determine that the input\325) 72 400 P +0.47 (s) 535.33 400 P +-0.29 (length were a multiple of the block size. W) 72 380 P +-0.29 (ith ) 276.05 380 P +3 F +-0.29 (bdes) 291.43 380 P +0 F +-0.29 (, the plaintext contents of the last block of input) 313.41 380 P +0.31 (for such a \336le is known \050a block with all bits zero\051. W) 72 360 P +0.31 (ith ) 333.99 360 P +3 F +0.31 (des) 349.96 360 P +0 F +0.31 (, the plaintext contents of that block) 365.95 360 P +0.73 (are not known. Cryptanalytically) 72 340 P +0.73 (, given the information about the strength of the DES currently) 231.29 340 P +0.2 (known, it is widely believed that known plaintext attacks are infeasible +\050see for example [1]\051 and) 72 320 P +1.86 (so initializing and invoking the pseudorandom number generator seems unnecessary) 72 300 P +1.86 (. But this) 492.63 300 P +(means that ciphertexts produced from a plaintext by ) 72 280 T +3 F +(bdes) 324.48 280 T +0 F +( and ) 346.47 280 T +3 F +(des) 369.78 280 T +0 F +( will dif) 385.77 280 T +(fer in the last block.) 423.54 280 T +4 F +(Refer) 72 248 T +(ences) 100.41 248 T +0 F +([1]) 72 224 T +0.37 (D. Denning, \322The Data Encryption Standard: Fifteen Y) 108 224 P +0.37 (ears of Public Scrutiny) 374.87 224 P +0.37 (,\323 ) 484.8 224 P +3 F +0.37 (Pr) 496.49 224 P +0.37 (oceed-) 508.04 224 P +-0.47 (ings of the Sixth Annual Computer Security Applications Confer) 108 204 P +-0.47 (ence) 411.65 204 P +0 F +-0.47 ( pp. x\320xv \050Dec. 1990\051.) 433.62 204 P +([2]) 72 180 T +(A. Konheim, ) 108 180 T +3 F +(Cryptography: A Primer) 173.29 180 T +0 F +(, John W) 291.4 180 T +(iley and Sons, Inc., New Y) 333.9 180 T +(ork, NY \0501981\051.) 461.94 180 T +([3]) 72 156 T +3 F +0.63 (DES Modes of Operation) 108 156 P +0 F +0.63 (, Federal Information Processing Standards Publication 81, Na-) 231.47 156 P +-0.07 (tional Bureau of Standards, U.S. Department of Commerce, W) 108 136 P +-0.07 (ashington, DC \050Dec. 1980\051.) 407.62 136 P +([4]) 72 112 T +3 F +(UNIX User) 108 112 T +(\325) 162.74 112 T +(s Manual) 165.18 112 T +0 F +(, Sun Microsystems Inc., Mountain V) 210.16 112 T +(iew) 390 112 T +(, CA \050Mar) 406.54 112 T +(. 1988\051.) 455.51 112 T +4 F +(Appendix. The UNIX System Manual Page for ) 72 80 T +1 F +(bdes) 313.2 80 T +FMENDPAGE +%%EndPage: "7" 10 +1 11 /Times-Bold FMDEFINEFONT +%%Page: "8" 10 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 8 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +1 F +0 X +(NAME) 72 712.67 T +0 F +(bdes - encrypt/decrypt using the Data Encryption Standard) 108 689 T +1 F +(SYNOPSIS) 72 663.67 T +4 F +(bdes) 108 640 T +0 F +( [) 131.33 640 T +3 F +( ) 138.32 640 T +4 F +(-abdp) 141.32 640 T +0 F +( ] [ ) 171.31 640 T +4 F +(-F) 188.3 640 T +0 F +( ) 199.62 640 T +3 F +(b) 202.62 640 T +0 F +( ] [ ) 208.61 640 T +4 F +(-f) 225.6 640 T +0 F +( ) 233.58 640 T +3 F +(b) 236.58 640 T +0 F +( ] [ ) 242.58 640 T +4 F +(-k) 259.56 640 T +0 F +( ) 270.22 640 T +3 F +(key) 273.22 640 T +0 F +( ] [ ) 289.2 640 T +4 F +(-m) 306.18 640 T +0 F +( ) 320.16 640 T +3 F +(b) 323.16 640 T +0 F +( ] [ ) 329.16 640 T +4 F +(-o) 346.14 640 T +0 F +( ) 356.13 640 T +3 F +(b) 359.13 640 T +0 F +( ] [ ) 365.13 640 T +4 F +(-v) 382.11 640 T +0 F +( ) 392.1 640 T +3 F +(vector) 395.1 640 T +0 F +( ]) 425.07 640 T +1 F +(DESCRIPTION) 72 614.67 T +3 F +-0.69 (Bdes) 108 591 P +0 F +-0.69 ( reads from the standard input and writes on the standard output. It implements all DES) 131.32 591 P +-0.09 (modes of operation described in FIPS PUB 81 including alternative cipher feedback mode) 108 577 P +0.74 (and both authentication modes. All modes but the electronic code book mode require an) 108 563 P +-0.14 (initialization vector; if none is supplied, the zero vector is used. T) 108 549 P +-0.14 (o protect the key and ini-) 420.44 549 P +0.29 (tialization vector from being read by) 108 535 P +3 F +0.29 ( ps) 284.98 535 P +0 F +0.29 (\0501\051, ) 298.94 535 P +3 F +0.29 (bdes ) 319.21 535 P +0 F +0.29 (hides its ar) 344.48 535 P +0.29 (guments on entry) 396.81 535 P +0.29 (. If no ) 479.89 535 P +3 F +0.29 (key ) 512.74 535 P +0 F +0.29 (is) 532 535 P +-0.61 (given, one is requested from the controlling terminal if that can be opened, or from the stan-) 108 521 P +(dard input if not.) 108 507 T +-0.17 (The key and initialization vector are taken as sequences of ) 108 489 P +5 F +-0.14 (ASCII) 389.38 489 P +0 F +-0.17 ( characters which are then) 415.48 489 P +-0.35 (mapped into their bit representations. If either begins with +\3240x\325 or \3240X\325, that one is taken as) 108 475 P +1.02 (a sequence of hexadecimal digits indicating the bit pattern; if either begins with \3240b\325 or) 108 461 P +-0.73 (\3240B\325, that one is taken as a sequence of binary digits +indicating the bit pattern. In either case,) 108 447 P +-0.37 (only the leading 64 bits of the key or initialization vector are used, and if fewer than 64 bits) 108 433 P +0.35 (are provided, enough 0 bits are appended to pad the key to 64 bits. Note that if the key is) 108 419 P +0.03 (not entered on the command line, it is interpreted in the same way) 108 405 P +0.03 (, because with 4.4 BSD,) 424.31 405 P +-0.36 (the password reading function ) 108 391 P +3 F +-0.36 (getpass) 254.45 391 P +0 F +-0.36 (\0503\051 allows enough characters for either hex or binary) 290.43 391 P +(keys to be entered.) 108 377 T +0.04 (According to the DES standard, the low-order bit of each character in the key string is de-) 108 359 P +-0.18 (leted. Since most ) 108 345 P +5 F +-0.15 (ASCII) 192.75 345 P +0 F +-0.18 ( representations set the high-order bit to 0, simply deleting the low-) 218.84 345 P +-0.29 (order bit ef) 108 331 P +-0.29 (fectively reduces the size of the key space from 2) 160.49 331 P +5 F +-0.24 (56) 394.67 335.8 P +0 F +-0.29 ( to 2) 404.67 331 P +5 F +-0.24 (48) 425.41 335.8 P +0 F +-0.29 ( keys. T) 435.4 331 P +-0.29 (o prevent this,) 472.29 331 P +-0.46 (the high-order bit must be a function depending in part upon the low-order bit; so, the high-) 108 317 P +0.11 (order bit is set to whatever value gives odd parity) 108 303 P +0.11 (. This preserves the key space size. Note) 345.05 303 P +(this resetting of the parity bit is ) 108 289 T +3 F +(not) 260.92 289 T +0 F +( done if the key is given in binary or hex.) 276.24 289 T +-0.38 (By default, the standard input is encrypted using cipher block chaining mode and is written) 108 271 P +0.18 (to the standard output. Using the same key for encryption and decryption preserves plain-) 108 257 P +(text, so) 108 243 T +( bdes ) 225.81 225 T +3 F +(key) 253.79 225 T +0 F +( < plaintext | bdes \320i ) 269.77 225 T +3 F +(key) 370.21 225 T +0 F +( ) 386.19 225 T +(is a very expensive equivalent of ) 108 201 T +3 F +(cat) 268.54 201 T +0 F +(\0501\051.) 283.2 201 T +(Options are:) 108 183 T +( ) 108 165 T +4 F +(\320a) 111 165 T +0 F +-0.75 (The key and initialization vector strings are to be taken as ) 144 165 P +5 F +-0.62 (ASCII) 415.89 165 P +0 F +-0.75 ( suppressing the spe-) 441.98 165 P +0.3 (cial interpretation given to leading \3240x\325, \3240X\325, \3240b\325, +and \3240B\325 characters. Note this) 144 151 P +(\337ag applies to ) 144 137 T +3 F +(both) 214.29 137 T +0 F +( the key and initialization vector) 235.62 137 T +(.) 389.85 137 T +4 F +(\320b) 108 119 T +0 F +(Use electronic code book mode.) 144 119 T +4 F +(\320d) 108 101 T +0 F +(Decrypt the input.) 144 101 T +FMENDPAGE +%%EndPage: "8" 11 +%%Page: "9" 11 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 9 of 11) 479.71 34.7 T +72 72 540 720 R +7 X +V +4 F +0 X +(\320f) 108 712 T +0 F +( ) 117.99 712 T +3 F +(b) 120.99 712 T +0 F +-0.29 (Use ) 144 712 P +3 F +-0.29 (b) 165.36 712 P +0 F +-0.29 (-bit cipher feedback mode. Currently ) 171.35 712 P +3 F +-0.29 (b) 350.42 712 P +0 F +-0.29 ( must be a multiple of 8 between 8 and) 356.42 712 P +(64 inclusive \050this does not conform to the standard CFB mode speci\336cation\051.) 144 698 T +4 F +(\320F) 108 680 T +0 F +( ) 121.32 680 T +3 F +(b) 124.32 680 T +0 F +-0.29 (Use ) 144 680 P +3 F +-0.29 (b) 165.36 680 P +0 F +-0.29 (-bit alternative cipher feedback mode. Currently ) 171.36 680 P +3 F +-0.29 (b) 403.77 680 P +0 F +-0.29 ( must be a multiple of 7 be-) 409.77 680 P +-0.12 (tween 7 and 56 inclusive \050this does not conform to the alternative CFB mode spec-) 144 666 P +(i\336cation\051.) 144 652 T +4 F +(\320k) 108 634 T +0 F +( ) 120.67 634 T +3 F +(key) 123.66 634 T +0 F +0.37 (Use the string ) 144 616 P +3 F +0.37 (key) 214.74 616 P +0 F +0.37 ( as the cryptographic key) 230.72 616 P +0.37 (. If this ar) 352.01 616 P +0.37 (gument is not given, the user) 399.54 616 P +(will be prompted for the key) 144 602 T +(.) 280.12 602 T +4 F +(\320m) 108 584 T +0 F +( ) 123.99 584 T +3 F +(b) 126.99 584 T +0 F +0.71 (Compute a message authentication code \050MAC\051 of ) 144 584 P +3 F +0.71 (b) 395.78 584 P +0 F +0.71 ( bits on the input. ) 401.77 584 P +3 F +0.71 (b) 491.94 584 P +0 F +0.71 ( must be) 497.94 584 P +0.11 (between 1 and 64 inclusive; if ) 144 570 P +3 F +0.11 (b) 291.87 570 P +0 F +0.11 ( is not a multiple of 8, enough 0 bits will be added) 297.86 570 P +-0.44 (to pad the MAC length to the nearest multiple of 8. Only the MAC is output. MACs) 144 556 P +(are only available in cipher block chaining mode or in cipher feedback mode.) 144 542 T +4 F +(\320o) 108 524 T +0 F +( ) 119.99 524 T +3 F +(b) 122.99 524 T +0 F +-0.34 (Use ) 144 524 P +3 F +-0.34 (b) 165.31 524 P +0 F +-0.34 (-bit output feedback mode. Currently ) 171.31 524 P +3 F +-0.34 (b) 350.83 524 P +0 F +-0.34 ( must be a multiple of 8 between 8 and) 356.83 524 P +(64 inclusive \050this does not conform to the OFB mode speci\336cation\051.) 144 510 T +4 F +(\320p) 108 492 T +0 F +-0.14 (Disable the resetting of the parity bit. This \337ag forces the parity bit of the key to be) 144 492 P +0.03 (used as typed, rather than making each character be of odd parity) 144 478 P +0.03 (. It is used only if) 455.91 478 P +(the key is given in ) 144 464 T +5 F +(ASCII) 234.95 464 T +0 F +(.) 261.04 464 T +4 F +(\320v) 108 446 T +0 F +( ) 119.99 446 T +3 F +(vector) 122.99 446 T +0 F +-0.5 (Set the initialization vector to ) 144 428 P +3 F +-0.5 (v) 286.44 428 P +0 F +-0.5 (; the vector is interpreted in the same way as the key) 291.76 428 P +-0.5 (.) 537 428 P +(The vector is ignored in electronic codebook mode.) 144 414 T +-0.55 (The DES is considered a very strong cryptosystem, and other than table lookup attacks, key) 108 396 P +0.24 (search attacks, and Hellman\325) 108 382 P +0.24 (s time-memory tradeof) 246.61 382 P +0.24 (f \050all of which are very expensive and) 356.8 382 P +0.66 (time-consuming\051, no cryptanalytic methods for breaking the DES are known in the open) 108 368 P +0.33 (literature. No doubt the choice of keys and key security are the most vulnerable aspect of) 108 354 P +3 F +(bdes) 108 340 T +0 F +(.) 129.98 340 T +4 F +(IMPLEMENT) 72 314 T +(A) 146.41 314 T +(TION NOTES) 154.18 314 T +0 F +0.57 (For implementors wishing to write software compatible with this program, the following) 108 290 P +-0.23 (notes are provided. This software is completely compatible with the implementation of the) 108 276 P +(data encryption standard distributed by Sun Microsystems, Inc.) 108 262 T +0.11 (In the ECB and CBC modes, plaintext is encrypted in units of 64 bits \0508 bytes, also called) 108 244 P +0.52 (a block\051. T) 108 230 P +0.52 (o ensure that the plaintext \336le is encrypted correctly) 160.49 230 P +0.52 (, ) 413.01 230 P +3 F +0.52 (bdes ) 419.53 230 P +0 F +0.52 (will \050internally\051 ap-) 445.03 230 P +0.29 (pend from 1 to 8 bytes, the last byte containing an integer stating how many bytes of that) 108 216 P +-0.71 (\336nal block are from the plaintext \336le, and encrypt the resulting block. Hence, when decrypt-) 108 202 P +0.27 (ing, the last block may contain from 0 to 7 characters present in the plaintext \336le, and the) 108 188 P +-0.59 (last byte tells how many) 108 174 P +-0.59 (. Note that if during decryption the last byte of the \336le does not con-) 221.46 174 P +0.41 (tain an integer between 0 and 7, either the \336le has been corrupted or an incorrect key has) 108 160 P +0.48 (been given. A similar mechanism is used for the OFB and CFB modes, except that those) 108 146 P +0.26 (simply require the length of the input to be a multiple of the mode size, and the \336nal byte) 108 132 P +-0.73 (contains an integer between 0 and one less than the number of bytes being used as the mode.) 108 118 P +(\050This was another reason that the mode size must be a multiple of 8 for those modes.\051) 108 104 T +FMENDPAGE +%%EndPage: "9" 12 +%%Page: "10" 12 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 10 of 11) 473.71 34.7 T +72 72 540 720 R +7 X +V +0 X +0.94 (Unlike Sun\325) 108 712 P +0.94 (s implementation, unused bytes of that last block are not \336lled with random) 166.58 712 P +0.57 (data, but instead contain what was in those byte positions in the preceding block. This is) 108 698 P +(quicker and more portable, and does not weaken the encryption signi\336cantly) 108 684 T +(.) 473.95 684 T +0.36 (If the key is entered in ) 108 666 P +5 F +0.3 (ASCII) 220.76 666 P +0 F +0.36 (, the parity bits of the key characters are set so that each key) 246.85 666 P +1.03 (character is of odd parity) 108 652 P +1.03 (. Unlike Sun\325) 231.23 652 P +1.03 (s implementation, it is possible to enter binary or) 296.92 652 P +-0.57 (hexadecimal keys on the command line, and if this is done, the parity bits are ) 108 638 P +3 F +-0.57 (not ) 472.85 638 P +0 F +-0.57 (reset. This) 490.61 638 P +(allows testing using arbitrary bit patterns as keys.) 108 624 T +0.64 (The Sun implementation always uses an initialization vector of 0 \050that is, all zeroes\051. By) 108 606 P +(default, ) 108 592 T +3 F +(bdes ) 147.3 592 T +0 F +(does too, but this may be changed from the command line.) 172.29 592 T +4 F +(FILES) 72 566 T +0 F +(/dev/tty) 108 542 T +(controlling terminal for typed key) 180 542 T +4 F +(SEE ALSO) 72 516 T +3 F +(crypt) 108 492 T +0 F +(\0501\051, ) 132.65 492 T +3 F +(crypt) 152.63 492 T +0 F +(\0503\051) 177.27 492 T +3 F +-0.4 (Data Encryption Standar) 108 474 P +-0.4 (d) 228.02 474 P +0 F +-0.4 (, Federal Information Processing Standard #46, National Bureau) 234.02 474 P +(of Standards, U.S. Department of Commerce, W) 108 460 T +(ashington DC \050Jan. 1977\051.) 340.2 460 T +3 F +0.16 (DES) 108 442 P +0 F +0.16 ( ) 129.98 442 P +3 F +0.16 (Modes of Operation, ) 133.15 442 P +0 F +0.16 (Federal Information Processing Standard #81, National Bureau) 236.24 442 P +(of Standards, U.S. Department of Commerce, W) 108 428 T +(ashington DC \050Dec. 1980\051.) 340.2 428 T +2.75 (Dorothy Denning, ) 108 410 P +3 F +2.75 (Cryptography and Data Security) 203.77 410 P +0 F +2.75 (, Addison-W) 368.8 410 P +2.75 (esley Publishing Co.,) 432.55 410 P +(Reading, MA \2511982.) 108 396 T +-0.19 ( Matt Bishop, \322Implementation Notes on ) 108 378 P +3 F +-0.19 (bdes) 305.76 378 P +0 F +-0.19 (\0501\051\323, T) 327.75 378 P +-0.19 (echnical Report PCS-TR-91-158, De-) 359.35 378 P +0.34 (partment of Mathematics and Computer Science, Dartmouth College, Hanover) 108 364 P +0.34 (, NH \050Apr) 488.01 364 P +0.34 (.) 537 364 P +(1991\051.) 108 350 T +4 F +(CAUTION) 72 324 T +0 F +-0.55 (Certain speci\336c keys should be avoided because they introduce potential weaknesses; these) 108 300 P +-0.44 (keys, called the ) 108 286 P +3 F +-0.44 (weak) 183.95 286 P +0 F +-0.44 ( and ) 208.6 286 P +3 F +-0.44 (semiweak) 231.03 286 P +0 F +-0.44 ( keys, are \050in hex notation, where ) 277.66 286 P +6 F +-1.06 (p) 437.45 286 P +0 F +-0.44 ( is either ) 444.64 286 P +6 F +-1.06 (0) 487.63 286 P +0 F +-0.44 ( or ) 494.82 286 P +6 F +-1.06 (1) 509.93 286 P +0 F +-0.44 (, and) 517.12 286 P +6 F +(P) 108 272 T +0 F +( is either ) 115.2 272 T +6 F +(e) 159.5 272 T +0 F +( or ) 166.7 272 T +6 F +(f) 182.68 272 T +0 F +(\051:) 189.88 272 T +6 F +(0x0p0p0p0p0p0p0p0p) 144 254 T +(0x0p1P0p1P0p0P0p0P) 360 254 T +(0x0pep0pep0pfp0pfp) 144 236 T +(0x0pfP0pfP0pfP0pfP) 360 236 T +(0x1P0p1P0p0P0p0P0p) 144 218 T +(0x1P1P1P1P0P0P0P0P) 360 218 T +(0x1Pep1Pep0Pfp0Pfp) 144 200 T +(0x1PfP1PfP0PfP0PfP) 360 200 T +(0xep0pep0pfp0pfp0p) 144 182 T +(0xep1Pep1pfp0Pfp0P) 360 182 T +(0xepepepepepepepep) 144 164 T +(0xepfPepfPfpfPfpfP) 360 164 T +(0xfP0pfP0pfP0pfP0p) 144 146 T +(0xfP1PfP1PfP0PfP0P) 360 146 T +(0xfPepfPepfPepfPep) 144 128 T +(0xfPfPfPfPfPfPfPfP) 360 128 T +0 F +0.13 (The weakness of these keys is inherent in the DES algorithm \050see for example Moore and) 108 110 P +-0.57 (Simmons, \322Cycle structure of the DES with weak and semi-weak keys,\323) 108 96 P +3 F +-0.57 ( Advances in Cryp-) 449.43 96 P +(tology \320 Crypto \32486 Pr) 108 82 T +(oceedings) 216.83 82 T +0 F +(, Springer) 264.79 82 T +(-V) 311.85 82 T +(erlag New Y) 323.17 82 T +(ork, \2511987, pp. 9-32\051.) 383.25 82 T +FMENDPAGE +%%EndPage: "10" 13 +%%Page: "11" 13 +612 792 0 FMBEGINPAGE +72 745.99 540 756 R +7 X +0 K +V +72 32.69 540 42.7 R +V +0 F +0 X +(Page 11 of 11) 473.71 34.7 T +72 72 540 720 R +7 X +V +4 F +0 X +(BUGS) 72 712 T +0 F +-0.18 (There is a controversy raging over whether the DES will still be secure in a few years. The) 108 688 P +0.31 (advent of special-purpose hardware could reduce the cost of any of the methods of attack) 108 674 P +(named above so that they are no longer computationally infeasible.) 108 660 T +0.32 (Programs which display programs\325 ar) 108 642 P +0.32 (guments may compromise the key and initialization) 289.59 642 P +0.76 (vector if they are speci\336ed on the command line. T) 108 628 P +0.76 (o avoid this ) 358.46 628 P +3 F +0.76 (bdes) 419.7 628 P +0 F +0.76 ( overwrites its ar) 441.68 628 P +0.76 (gu-) 524.01 628 P +(ments. However) 108 614 T +(, the obvious race cannot currently be avoided.) 186.12 614 T +0.25 (As the key or key schedule is kept in memory throughout the run of this program, the en-) 108 596 P +(cryption can be compromised if memory is readable.) 108 582 T +-0.4 (There is no warranty of merchantability nor any warranty of \336tness for a particular purpose) 108 564 P +0.05 (nor any other warranty) 108 550 P +0.05 (, either express or implied, as to the accuracy of the enclosed mate-) 216.95 550 P +(rials or as to their suitability for any particular purpose.) 108 536 T +-0.06 (Accordingly) 108 518 P +-0.06 (, the user assumes full responsibility for their use. Further) 167.18 518 P +-0.06 (, the author assumes) 442.93 518 P +-0.25 (no obligation to furnish any assistance of any kind whatsoever) 108 504 P +-0.25 (, or to furnish any additional) 404.69 504 P +(information or documentation.) 108 490 T +4 F +(AUTHOR) 72 464 T +0 F +-0.54 (Matt Bishop, Department of Mathematics and Computer Science, Bradley Hall, Dartmouth) 108 440 P +(College, Hanover) 108 426 T +(, NH 03755) 192.12 426 T +(Electronic mail addresses:) 108 408 T +(Internet: Matt.Bishop@dartmouth.edu) 108 390 T +(UUCP: decvax!dartvax!Matt.Bishop) 108 372 T +FMENDPAGE +%%EndPage: "11" 14 +%%Trailer +%%BoundingBox: 0 0 612 792 +%%Pages: 13 1 +%%DocumentFonts: Helvetica-Bold +%%+ Helvetica-BoldOblique +%%+ Times-Roman +%%+ Times-Bold +%%+ Times-BoldItalic +%%+ Times-Italic +%%+ Courier +%%+ Courier-Oblique +%%+ ZapfDingbats +%%+ Symbol +%%+ Courier-Bold diff --git a/usr.bin/biff/Makefile b/usr.bin/biff/Makefile new file mode 100644 index 0000000..81cb86b --- /dev/null +++ b/usr.bin/biff/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= biff + +.include diff --git a/usr.bin/biff/biff.1 b/usr.bin/biff/biff.1 new file mode 100644 index 0000000..89d560c --- /dev/null +++ b/usr.bin/biff/biff.1 @@ -0,0 +1,86 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)biff.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt BIFF 1 +.Os BSD 4 +.Sh NAME +.Nm biff +.Nd "be notified if mail arrives and who it is from" +.Sh SYNOPSIS +.Nm biff +.Op Cm ny +.Sh DESCRIPTION +.Nm Biff +informs the system whether you want to be notified when mail arrives +during the current terminal session. +.Pp +Options supported by +.Nm biff : +.Bl -tag -width 4n +.It Cm n +Disables notification. +.It Cm y +Enables notification. +.El +.Pp +When mail notification is enabled, the header and first few lines of +the message will be printed on your screen whenever mail arrives. +A +.Dq Li biff y +command is often included in the file +.Pa \&.login +or +.Pa \&.profile +to be executed at each login. +.Pp +.Nm Biff +operates asynchronously. +For synchronous notification use the +.Ar MAIL +variable of +.Xr sh 1 +or the +.Ar mail +variable of +.Xr csh 1 . +.Sh SEE ALSO +.Xr csh 1 , +.Xr mail 1 , +.Xr sh 1 , +.Xr comsat 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/biff/biff.c b/usr.bin/biff/biff.c new file mode 100644 index 0000000..8d816bf --- /dev/null +++ b/usr.bin/biff/biff.c @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)biff.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include + +static void usage __P((void)); +static void err __P((char *)); + +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb; + int ch; + char *name; + + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if ((name = ttyname(STDERR_FILENO)) == NULL) { + (void)fprintf(stderr, "biff: unknown tty\n"); + exit(2); + } + + if (stat(name, &sb)) + err(name); + + if (*argv == NULL) { + (void)printf("is %s\n", sb.st_mode&0100 ? "y" : "n"); + exit(sb.st_mode & 0100 ? 0 : 1); + } + + switch(argv[0][0]) { + case 'n': + if (chmod(name, sb.st_mode & ~0100) < 0) + err(name); + break; + case 'y': + if (chmod(name, sb.st_mode | 0100) < 0) + err(name); + break; + default: + usage(); + } + exit(sb.st_mode & 0100 ? 0 : 1); +} + +static void +err(name) + char *name; +{ + (void)fprintf(stderr, "biff: %s: %s\n", name, strerror(errno)); + exit(2); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: biff [y | n]\n"); + exit(2); +} diff --git a/usr.bin/cal/Makefile b/usr.bin/cal/Makefile new file mode 100644 index 0000000..aed0afa --- /dev/null +++ b/usr.bin/cal/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= cal + +.include diff --git a/usr.bin/cal/README b/usr.bin/cal/README new file mode 100644 index 0000000..638ac9d --- /dev/null +++ b/usr.bin/cal/README @@ -0,0 +1,42 @@ +The cal(1) date routines were written from scratch, basically from first +principles. The algorithm for calculating the day of week from any +Gregorian date was "reverse engineered". This was necessary as most of +the documented algorithms have to do with date calculations for other +calendars (e.g. julian) and are only accurate when converted to gregorian +within a narrow range of dates. + +1 Jan 1 is a Saturday because that's what cal says and I couldn't change +that even if I was dumb enough to try. From this we can easily calculate +the day of week for any date. The algorithm for a zero based day of week: + + calculate the number of days in all prior years (year-1)*365 + add the number of leap years (days?) since year 1 + (not including this year as that is covered later) + add the day number within the year + this compensates for the non-inclusive leap year + calculation + if the day in question occurs before the gregorian reformation + (3 sep 1752 for our purposes), then simply return + (value so far - 1 + SATURDAY's value of 6) modulo 7. + if the day in question occurs during the reformation (3 sep 1752 + to 13 sep 1752 inclusive) return THURSDAY. This is my + idea of what happened then. It does not matter much as + this program never tries to find day of week for any day + that is not the first of a month. + otherwise, after the reformation, use the same formula as the + days before with the additional step of subtracting the + number of days (11) that were adjusted out of the calendar + just before taking the modulo. + +It must be noted that the number of leap years calculation is sensitive +to the date for which the leap year is being calculated. A year that occurs +before the reformation is determined to be a leap year if its modulo of +4 equals zero. But after the reformation, a year is only a leap year if +its modulo of 4 equals zero and its modulo of 100 does not. Of course, +there is an exception for these century years. If the modulo of 400 equals +zero, then the year is a leap year anyway. This is, in fact, what the +gregorian reformation was all about (a bit of error in the old algorithm +that caused the calendar to be inaccurate.) + +Once we have the day in year for the first of the month in question, the +rest is trivial. diff --git a/usr.bin/cal/cal.1 b/usr.bin/cal/cal.1 new file mode 100644 index 0000000..80d95b2 --- /dev/null +++ b/usr.bin/cal/cal.1 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Kim Letkeman. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)cal.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt CAL 1 +.Os +.Sh NAME +.Nm cal +.Nd displays a calendar +.Sh SYNOPSIS +.Nm cal +.Op Fl jy +.Op Ar month Op Ar year +.Sh DESCRIPTION +.Nm Cal +displays a simple calendar. +If arguments are not specified, +the current month is displayed. +The options are as follows: +.Bl -tag -width Ds +.It Fl j +Display julian dates (days one-based, numbered from January 1). +.It Fl y +Display a calendar for the current year. +.El +.Pp +A single parameter specifies the year (1 - 9999) to be displayed; +note the year must be fully specified: +.Dq Li cal 89 +will +.Em not +display a calendar for 1989. +Two parameters denote the month (1 - 12) and year. +If no parameters are specified, the current month's calendar is +displayed. +.Pp +A year starts on Jan 1. +.Pp +The Gregorian Reformation is assumed to have occurred in 1752 on the 3rd +of September. +By this time, most countries had recognized the reformation (although a +few did not recognize it until the early 1900's.) +Ten days following that date were eliminated by the reformation, so the +calendar for that month is a bit unusual. +.Sh HISTORY +A +.Nm +command appeared in Version 6 AT&T UNIX. diff --git a/usr.bin/cal/cal.c b/usr.bin/cal/cal.c new file mode 100644 index 0000000..88d2538 --- /dev/null +++ b/usr.bin/cal/cal.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kim Letkeman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define THURSDAY 4 /* for reformation */ +#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ + +#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */ +#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ + +#define MAXDAYS 42 /* max slots in a month array */ +#define SPACE -1 /* used in day array */ + +static int days_in_month[2][13] = { + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, +}; + +int sep1752[MAXDAYS] = { + SPACE, SPACE, 1, 2, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}, j_sep1752[MAXDAYS] = { + SPACE, SPACE, 245, 246, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}, empty[MAXDAYS] = { + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}; + +char *month_names[12] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", +}; + +char *day_headings = " S M Tu W Th F S"; +char *j_day_headings = " S M Tu W Th F S"; + +/* leap year -- account for gregorian reformation in 1752 */ +#define leap_year(yr) \ + ((yr) <= 1752 ? !((yr) % 4) : \ + !((yr) % 4) && ((yr) % 100) || !((yr) % 400)) + +/* number of centuries since 1700, not inclusive */ +#define centuries_since_1700(yr) \ + ((yr) > 1700 ? (yr) / 100 - 17 : 0) + +/* number of centuries since 1700 whose modulo of 400 is 0 */ +#define quad_centuries_since_1700(yr) \ + ((yr) > 1600 ? ((yr) - 1600) / 400 : 0) + +/* number of leap years between year 1 and this year, not inclusive */ +#define leap_years_since_year_1(yr) \ + ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) + +int julian; + +void ascii_day __P((char *, int)); +void center __P((char *, int, int)); +void day_array __P((int, int, int *)); +int day_in_week __P((int, int, int)); +int day_in_year __P((int, int, int)); +void j_yearly __P((int)); +void monthly __P((int, int)); +void trim_trailing_spaces __P((char *)); +void usage __P((void)); +void yearly __P((int)); + +int +main(argc, argv) + int argc; + char **argv; +{ + struct tm *local_time; + time_t now; + int ch, month, year, yflag; + + yflag = 0; + while ((ch = getopt(argc, argv, "jy")) != EOF) + switch(ch) { + case 'j': + julian = 1; + break; + case 'y': + yflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + month = 0; + switch(argc) { + case 2: + if ((month = atoi(*argv++)) < 1 || month > 12) + errx(1, "illegal month value: use 1-12"); + /* FALLTHROUGH */ + case 1: + if ((year = atoi(*argv)) < 1 || year > 9999) + errx(1, "illegal year value: use 1-9999"); + break; + case 0: + (void)time(&now); + local_time = localtime(&now); + year = local_time->tm_year + 1900; + if (!yflag) + month = local_time->tm_mon + 1; + break; + default: + usage(); + } + + if (month) + monthly(month, year); + else if (julian) + j_yearly(year); + else + yearly(year); + exit(0); +} + +#define DAY_LEN 3 /* 3 spaces per day */ +#define J_DAY_LEN 4 /* 4 spaces per day */ +#define WEEK_LEN 20 /* 7 * 3 - one space at the end */ +#define J_WEEK_LEN 27 /* 7 * 4 - one space at the end */ +#define HEAD_SEP 2 /* spaces between day headings */ +#define J_HEAD_SEP 2 + +void +monthly(month, year) + int month, year; +{ + int col, row, len, days[MAXDAYS]; + char *p, lineout[30]; + + day_array(month, year, days); + len = sprintf(lineout, "%s %d", month_names[month - 1], year); + (void)printf("%*s%s\n%s\n", + ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "", + lineout, julian ? j_day_headings : day_headings); + for (row = 0; row < 6; row++) { + for (col = 0, p = lineout; col < 7; col++, + p += julian ? J_DAY_LEN : DAY_LEN) + ascii_day(p, days[row * 7 + col]); + *p = '\0'; + trim_trailing_spaces(lineout); + (void)printf("%s\n", lineout); + } +} + +void +j_yearly(year) + int year; +{ + int col, *dp, i, month, row, which_cal; + int days[12][MAXDAYS]; + char *p, lineout[80]; + + (void)sprintf(lineout, "%d", year); + center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0); + (void)printf("\n\n"); + for (i = 0; i < 12; i++) + day_array(i + 1, year, days[i]); + (void)memset(lineout, ' ', sizeof(lineout) - 1); + lineout[sizeof(lineout) - 1] = '\0'; + for (month = 0; month < 12; month += 2) { + center(month_names[month], J_WEEK_LEN, J_HEAD_SEP); + center(month_names[month + 1], J_WEEK_LEN, 0); + (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "", + j_day_headings); + for (row = 0; row < 6; row++) { + for (which_cal = 0; which_cal < 2; which_cal++) { + p = lineout + which_cal * (J_WEEK_LEN + 2); + dp = &days[month + which_cal][row * 7]; + for (col = 0; col < 7; col++, p += J_DAY_LEN) + ascii_day(p, *dp++); + } + *p = '\0'; + trim_trailing_spaces(lineout); + (void)printf("%s\n", lineout); + } + } + (void)printf("\n"); +} + +void +yearly(year) + int year; +{ + int col, *dp, i, month, row, which_cal; + int days[12][MAXDAYS]; + char *p, lineout[80]; + + (void)sprintf(lineout, "%d", year); + center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0); + (void)printf("\n\n"); + for (i = 0; i < 12; i++) + day_array(i + 1, year, days[i]); + (void)memset(lineout, ' ', sizeof(lineout) - 1); + lineout[sizeof(lineout) - 1] = '\0'; + for (month = 0; month < 12; month += 3) { + center(month_names[month], WEEK_LEN, HEAD_SEP); + center(month_names[month + 1], WEEK_LEN, HEAD_SEP); + center(month_names[month + 2], WEEK_LEN, 0); + (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP, + "", day_headings, HEAD_SEP, "", day_headings); + for (row = 0; row < 6; row++) { + for (which_cal = 0; which_cal < 3; which_cal++) { + p = lineout + which_cal * (WEEK_LEN + 2); + dp = &days[month + which_cal][row * 7]; + for (col = 0; col < 7; col++, p += DAY_LEN) + ascii_day(p, *dp++); + } + *p = '\0'; + trim_trailing_spaces(lineout); + (void)printf("%s\n", lineout); + } + } + (void)printf("\n"); +} + +/* + * day_array -- + * Fill in an array of 42 integers with a calendar. Assume for a moment + * that you took the (maximum) 6 rows in a calendar and stretched them + * out end to end. You would have 42 numbers or spaces. This routine + * builds that array for any month from Jan. 1 through Dec. 9999. + */ +void +day_array(month, year, days) + int month, year; + int *days; +{ + int day, dw, dm; + + if (month == 9 && year == 1752) { + memmove(days, + julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int)); + return; + } + memmove(days, empty, MAXDAYS * sizeof(int)); + dm = days_in_month[leap_year(year)][month]; + dw = day_in_week(1, month, year); + day = julian ? day_in_year(1, month, year) : 1; + while (dm--) + days[dw++] = day++; +} + +/* + * day_in_year -- + * return the 1 based day number within the year + */ +int +day_in_year(day, month, year) + int day, month, year; +{ + int i, leap; + + leap = leap_year(year); + for (i = 1; i < month; i++) + day += days_in_month[leap][i]; + return (day); +} + +/* + * day_in_week + * return the 0 based day number for any date from 1 Jan. 1 to + * 31 Dec. 9999. Assumes the Gregorian reformation eliminates + * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all + * missing days. + */ +int +day_in_week(day, month, year) + int day, month, year; +{ + long temp; + + temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + + day_in_year(day, month, year); + if (temp < FIRST_MISSING_DAY) + return ((temp - 1 + SATURDAY) % 7); + if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS)) + return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); + return (THURSDAY); +} + +void +ascii_day(p, day) + char *p; + int day; +{ + int display, val; + static char *aday[] = { + "", + " 1", " 2", " 3", " 4", " 5", " 6", " 7", + " 8", " 9", "10", "11", "12", "13", "14", + "15", "16", "17", "18", "19", "20", "21", + "22", "23", "24", "25", "26", "27", "28", + "29", "30", "31", + }; + + if (day == SPACE) { + memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN); + return; + } + if (julian) { + if (val = day / 100) { + day %= 100; + *p++ = val + '0'; + display = 1; + } else { + *p++ = ' '; + display = 0; + } + val = day / 10; + if (val || display) + *p++ = val + '0'; + else + *p++ = ' '; + *p++ = day % 10 + '0'; + } else { + *p++ = aday[day][0]; + *p++ = aday[day][1]; + } + *p = ' '; +} + +void +trim_trailing_spaces(s) + char *s; +{ + char *p; + + for (p = s; *p; ++p) + continue; + while (p > s && isspace(*--p)) + continue; + if (p > s) + ++p; + *p = '\0'; +} + +void +center(str, len, separate) + char *str; + int len; + int separate; +{ + + len -= strlen(str); + (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, ""); + if (separate) + (void)printf("%*s", separate, ""); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n"); + exit(1); +} diff --git a/usr.bin/calendar/Makefile b/usr.bin/calendar/Makefile new file mode 100644 index 0000000..afa891e --- /dev/null +++ b/usr.bin/calendar/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= calendar + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m 444 \ + ${.CURDIR}/calendars/calendar.* ${DESTDIR}/usr/share/calendar + +.include diff --git a/usr.bin/calendar/calendar.1 b/usr.bin/calendar/calendar.1 new file mode 100644 index 0000000..1ffa5e5 --- /dev/null +++ b/usr.bin/calendar/calendar.1 @@ -0,0 +1,145 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93 +.\" +.Dd June 29, 1993 +.Dt CALENDAR 1 +.Os +.Sh NAME +.Nm calendar +.Nd reminder service +.Sh SYNOPSIS +.Nm calendar +.Op Fl a +.Sh DESCRIPTION +.Nm Calendar +checks the current directory for a file named +.Pa calendar +and displays lines that begin with either today's date +or tomorrow's. +On Fridays, events on Friday through Monday are displayed. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl a +Process the ``calendar'' files of all users and mail the results +to them. +This requires super-user privileges. +.El +.Pp +Lines should begin with a month and day. +They may be entered in almost any format, either numeric or as character +strings. +A single asterisk (``*'') matches every month. +A day without a month matches that day of every week. +A month without a day matches the first of that month. +Two numbers default to the month followed by the day. +Lines with leading tabs default to the last entered date, allowing +multiple line specifications for a single date. +By convention, dates followed by an asterisk are not fixed, i.e., change +from year to year. +.Pp +The ``calendar'' file is preprocessed by +.Xr cpp 1 , +allowing the inclusion of shared files such as company holidays or +meetings. +If the shared file is not referenced by a full pathname, +.Xr cpp 1 +searches in the current (or home) directory first, and then in the +directory +.Pa /usr/share/calendar . +Empty lines and lines protected by the C commenting syntax +.Pq Li /* ... */ +are ignored. +.Pp +Some possible calendar entries: +.Bd -unfilled -offset indent +#include +#include + +6/15 ... June 15 (if ambiguous, will default to month/day). +Jun. 15 ... June 15. +15 June ... June 15. +Thursday ... Every Thursday. +June ... Every June 1st. +15 * ... 15th of every month. +.Ed +.Sh FILES +The following default calendar files are provided: +.Pp +.Bl -tag -width calendar.christian -compact +.It Pa calendar.birthday +Births and deaths of famous (and not-so-famous) people. +.It Pa calendar.christian +Christian holidays. +This calendar should be updated yearly by the local system administrator +so that roving holidays are set correctly for the current year. +.It Pa calendar.computer +Days of special significance to computer people. +.It Pa calendar.history +Everything else, mostly U. S. historical events. +.It Pa calendar.holiday +Other holidays, including the not-well-known, obscure, and +.Em really +obscure. +.It Pa calendar.judaic +Jewish holidays. +This calendar should be updated yearly by the local system administrator +so that roving holidays are set correctly for the current year. +.It Pa calendar.music +Musical events, births, and deaths. +Strongly oriented toward rock 'n' roll. +.It Pa calendar.usholiday +U.S. holidays. +This calendar should be updated yearly by the local system administrator +so that roving holidays are set correctly for the current year. +.El +.Sh SEE ALSO +.Xr at 1 , +.Xr cpp 1 , +.Xr cron 8 +.Xr mail 1 , +.Sh COMPATIBILITY +The +.Nm calendar +program previously selected lines which had the correct date anywhere +in the line. +This is no longer true, the date is only recognized when it occurs +first on the line. +.Sh HISTORY +A +.Nm +command appeared in Version 7 AT&T UNIX. +.Sh BUGS +.Nm Calendar +doesn't handle events that move around from year to year, i.e., +``the last Monday in April''. diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c new file mode 100644 index 0000000..95f1898 --- /dev/null +++ b/usr.bin/calendar/calendar.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +struct passwd *pw; +int doall; + +void cal __P((void)); +void closecal __P((FILE *)); +int getday __P((char *)); +int getfield __P((char *, char **, int *)); +int getmonth __P((char *)); +int isnow __P((char *)); +FILE *opencal __P((void)); +void settime __P((void)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + int ch; + + while ((ch = getopt(argc, argv, "-a")) != EOF) + switch (ch) { + case '-': /* backward contemptible */ + case 'a': + if (getuid()) { + errno = EPERM; + err(1, NULL); + } + doall = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc) + usage(); + + settime(); + if (doall) + while ((pw = getpwent()) != NULL) { + (void)setegid(pw->pw_gid); + (void)seteuid(pw->pw_uid); + if (!chdir(pw->pw_dir)) + cal(); + (void)seteuid(0); + } + else + cal(); + exit(0); +} + +void +cal() +{ + register int printing; + register char *p; + FILE *fp; + int ch; + char buf[2048 + 1]; + + if ((fp = opencal()) == NULL) + return; + for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) { + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + else + while ((ch = getchar()) != '\n' && ch != EOF); + if (buf[0] == '\0') + continue; + if (buf[0] != '\t') + printing = isnow(buf) ? 1 : 0; + if (printing) + (void)fprintf(fp, "%s\n", buf); + } + closecal(fp); +} + +struct iovec header[] = { + "From: ", 6, + NULL, 0, + " (Reminder Service)\nTo: ", 24, + NULL, 0, + "\nSubject: ", 10, + NULL, 0, + "'s Calendar\nPrecedence: bulk\n\n", 30, +}; + +/* 1-based month, 0-based days, cumulative */ +int daytab[][14] = { + 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364, + 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, +}; +struct tm *tp; +int *cumdays, offset, yrdays; +char dayname[10]; + +void +settime() +{ + time_t now; + + (void)time(&now); + tp = localtime(&now); + if (isleap(tp->tm_year + 1900)) { + yrdays = DAYSPERLYEAR; + cumdays = daytab[1]; + } else { + yrdays = DAYSPERNYEAR; + cumdays = daytab[0]; + } + /* Friday displays Monday's events */ + offset = tp->tm_wday == 5 ? 3 : 1; + header[5].iov_base = dayname; + header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp); +} + +/* + * Possible date formats include any combination of: + * 3-charmonth (January, Jan, Jan) + * 3-charweekday (Friday, Monday, mon.) + * numeric month or day (1, 2, 04) + * + * Any character may separate them, or they may not be separated. Any line, + * following a line that is matched, that starts with "whitespace", is shown + * along with the matched line. + */ +int +isnow(endp) + char *endp; +{ + int day, flags, month, v1, v2; + +#define F_ISMONTH 0x01 +#define F_ISDAY 0x02 + flags = 0; + /* didn't recognize anything, skip it */ + if (!(v1 = getfield(endp, &endp, &flags))) + return (0); + if (flags & F_ISDAY || v1 > 12) { + /* found a day */ + day = v1; + /* if no recognizable month, assume just a day alone */ + if (!(month = getfield(endp, &endp, &flags))) + month = tp->tm_mon + 1; + } else if (flags & F_ISMONTH) { + month = v1; + /* if no recognizable day, assume the first */ + if (!(day = getfield(endp, &endp, &flags))) + day = 1; + } else { + v2 = getfield(endp, &endp, &flags); + if (flags & F_ISMONTH) { + day = v1; + month = v2; + } else { + /* F_ISDAY set, v2 > 12, or no way to tell */ + month = v1; + /* if no recognizable day, assume the first */ + day = v2 ? v2 : 1; + } + } + if (flags & F_ISDAY) + day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7); + day = cumdays[month] + day; + + /* if today or today + offset days */ + if (day >= tp->tm_yday && day <= tp->tm_yday + offset) + return (1); + /* if number of days left in this year + days to event in next year */ + if (yrdays - tp->tm_yday + day <= offset) + return (1); + return (0); +} + +int +getfield(p, endp, flags) + char *p, **endp; + int *flags; +{ + int val; + char *start, savech; + + for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p); + if (*p == '*') { /* `*' is current month */ + *flags |= F_ISMONTH; + *endp = p+1; + return (tp->tm_mon + 1); + } + if (isdigit(*p)) { + val = strtol(p, &p, 10); /* if 0, it's failure */ + for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p); + *endp = p; + return (val); + } + for (start = p; isalpha(*++p);); + savech = *p; + *p = '\0'; + if ((val = getmonth(start)) != 0) + *flags |= F_ISMONTH; + else if ((val = getday(start)) != 0) + *flags |= F_ISDAY; + else { + *p = savech; + return (0); + } + for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p); + *endp = p; + return (val); +} + +char path[MAXPATHLEN + 1]; + +FILE * +opencal() +{ + int fd, pdes[2]; + + /* open up calendar file as stdin */ + if (!freopen("calendar", "r", stdin)) { + if (doall) + return (NULL); + errx(1, "no calendar file."); + } + if (pipe(pdes) < 0) + return (NULL); + switch (vfork()) { + case -1: /* error */ + (void)close(pdes[0]); + (void)close(pdes[1]); + return (NULL); + case 0: + /* child -- stdin already setup, set stdout to pipe input */ + if (pdes[1] != STDOUT_FILENO) { + (void)dup2(pdes[1], STDOUT_FILENO); + (void)close(pdes[1]); + } + (void)close(pdes[0]); + execl(_PATH_CPP, "cpp", "-I.", _PATH_INCLUDE, NULL); + (void)fprintf(stderr, + "calendar: execl: %s: %s.\n", _PATH_CPP, strerror(errno)); + _exit(1); + } + /* parent -- set stdin to pipe output */ + (void)dup2(pdes[0], STDIN_FILENO); + (void)close(pdes[0]); + (void)close(pdes[1]); + + /* not reading all calendar files, just set output to stdout */ + if (!doall) + return (stdout); + + /* set output to a temporary file, so if no output don't send mail */ + (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); + if ((fd = mkstemp(path)) < 0) + return (NULL); + return (fdopen(fd, "w+")); +} + +void +closecal(fp) + FILE *fp; +{ + struct stat sbuf; + int nread, pdes[2], status; + char buf[1024]; + + if (!doall) + return; + + (void)rewind(fp); + if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) + goto done; + if (pipe(pdes) < 0) + goto done; + switch (vfork()) { + case -1: /* error */ + (void)close(pdes[0]); + (void)close(pdes[1]); + goto done; + case 0: + /* child -- set stdin to pipe output */ + if (pdes[0] != STDIN_FILENO) { + (void)dup2(pdes[0], STDIN_FILENO); + (void)close(pdes[0]); + } + (void)close(pdes[1]); + execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", + "\"Reminder Service\"", "-f", "root", NULL); + (void)fprintf(stderr, + "calendar: %s: %s.\n", _PATH_SENDMAIL, strerror(errno)); + _exit(1); + } + /* parent -- write to pipe input */ + (void)close(pdes[0]); + + header[1].iov_base = header[3].iov_base = pw->pw_name; + header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); + writev(pdes[1], header, 7); + while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) + (void)write(pdes[1], buf, nread); + (void)close(pdes[1]); +done: (void)fclose(fp); + (void)unlink(path); + while (wait(&status) >= 0); +} + +static char *months[] = { + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec", NULL, +}; + +int +getmonth(s) + register char *s; +{ + register char **p; + + for (p = months; *p; ++p) + if (!strncasecmp(s, *p, 3)) + return ((p - months) + 1); + return (0); +} + +static char *days[] = { + "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL, +}; + +int +getday(s) + register char *s; +{ + register char **p; + + for (p = days; *p; ++p) + if (!strncasecmp(s, *p, 3)) + return ((p - days) + 1); + return (0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: calendar [-a]\n"); + exit(1); +} diff --git a/usr.bin/calendar/calendars/calendar.birthday b/usr.bin/calendar/calendars/calendar.birthday new file mode 100644 index 0000000..0cb8cab --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.birthday @@ -0,0 +1,257 @@ +01/01 J.D. Salinger born, 1919 +01/01 Paul Revere born in Boston, 1735 +01/02 Isaac Asimov born in Petrovichi, Russian SFSR (now part of USSR), 1920 +01/04 George Washington Carver born in Missouri, 1864 +01/04 Jakob Grimm born, 1785 +01/04 Wilhelm Beer born, 1797, first astronomer to map Mars +01/05 DeWitt B. Brace born, 1859, inventor of spectrophotometer +01/10 Ethan Allen born, 1738 +01/11 Alexander Hamilton born in Nevis, British West Indies, 1757? +01/12 "Long" John Baldry is born in London, 1941 +01/13 Horatio Alger born, 1834 +01/13 Sophie Tucker born, 1884 +01/13 Wilhelm Wien born, 1864, Nobel prize for blackbody radiation laws +01/14 Albert Schweitzer born, 1875 +01/15 Martin Luther King, Jr. born +01/17 Benjamin Franklin born in Boston, 1706 +01/19 Edgar Allan Poe born in Boston, 1809 +01/19 Robert Edward Lee born in Stratford Estate, Virginia, 1807 +01/20 George Burns born, 1898 +01/21 Lenin died, 1924 +01/21 Thomas Jonathan "Stonewall" Jackson born in Clarksburg, VA, 1824 +01/22 Sir Francis Bacon born, 1561 +01/23 Ernst Abbe born, 1840, formulated diffraction theory +01/23 Humphrey Bogart born in New York City, 1899 +01/23 John Hancock born, 1737 +01/23 Joseph Hewes born, 1730 +01/23 Samuel Barber died, 1981 +01/24 John Belushi is born in Chicago, 1949 +01/25 Robert Burns born, 1759 +01/25 Virginia Woolf born, 1882 +01/25 W. Somerset Maugham born, 1874 +01/27 Samuel Gompers born, 1850 +01/30 Franklin Delano Roosevelt born in Hyde Park, New York, 1882 +01/31 Jackie Robinson born, 1919 +02/03 Gertrude Stein born, 1874 +02/05 Alex Harvey (SAHB) is born in Glasgow, Scotland, 1935 +02/06 King George VI of UK dies; his daughter becomes Elizabeth II, 1952 +02/07 Sinclair Lewis born, 1885 +02/08 Friedleib F. Runge born, 1795, father of paper chromatography +02/08 Jules Verne born in Nantes, France, 1828 +02/09 George Hartmann born, 1489, designed astrolabes, timepieces, etc. +02/10 Charles Lamb born, 1775 +02/10 William Allen White born, 1868 +02/11 Thos. Edison born, 1847 +02/11 William Henry Fox Talbot born, 1489, photographic pioneer +02/12 Abraham Lincoln born, 1809 +02/12 Charles Darwin born in Shrewsbury, England, 1809 +02/15 Galileo Galilei born in Pisa, Italy, 1564 +02/15 Susan B. Anthony born, 1820 +02/16 Pierre Bouguer born, 1698, founder of photometry +02/17 Federick Eugene Ives born, 1856, pioneer of halftone +02/17 Marion Anderson born, 1902 +02/17 T. J. Watson, Sr. born, 1874 +02/18 Ernst Mach born, 1838, philosopher & optics pioneer +02/19 Nicolas Copernicus born in Thorn, Poland, 1473 +02/20 Ludwig Boltzmann born, 1838, atomic physics pioneer +02/21 Alexis De Rochon born, 1838, developed the spyglass +02/22 George Washington born, 1732 +02/22 Pierre Jules Cesar Janssen born, 1838, found hydrogen in the sun +02/23 W.E.B. DuBois born, 1868 +02/24 Winslow Homer born, 1836 +02/25 George Harrison born in Liverpool, England, 1943 +02/25 Renoir born, 1841 +02/26 Dominique Francois Jean Arago born, 1786; + observed "Poisson's spot" cf June 21 +02/28 Michel de Mantaigne born, 1533 +02/29 Herman Hollerith born, 1860 +03/01 David Niven born, 1910 +03/02 Dr. Seuss born, 1904 +03/04 Casimir Pulaski born, 1747 +03/05 John Belushi dies in Los Angeles, 1982 +03/07 Aristotle died, 322BC +03/07 Sir John Frederick William Herschel born, 1792, astronomer +03/08 Alvan Clark born, 1804, astronomer & lens manufacturer +03/08 Howard Aiken born, 1900 +03/11 Robert Treat Paine born, 1737 +03/11 Vannevar Bush born, 1890 +03/12 Gustav Robert Kirchhoff born, 1824, physicist +03/14 Albert Einstein born, 1879 +03/14 Casey Jones born, 1864 +03/14 Giovanni Virginia Schiaparelli born, 1835, astronomer; + named Mars "canals" +03/14 Jean Baptiste Joseph Fourier born, 1768, mathematician & physicist +03/16 George Clymer born, 1739 +03/16 James Madison born, 1751 +03/24 Harry Houdini born, 1874 +03/26 Benjamin Thompson born, 1753, Count Rumford; physicist +03/27 Wilhelm Conrad Roentgen born, 1845, discoverer of X-rays +03/28 Pierre Simon de Laplace born, 1749, mathematician & astronomer +03/30 Francisco Jose de Goya born, 1746 +03/30 Sean O'Casey born, 1880 +03/30 Vincent Van Gogh born, 1853 +03/31 Descartes born, 1596 +03/31 Rene Descartes born, 1596, mathematician & philosopher +04/03 Washington Irving born, 1783 +04/05 Thomas Hobbes born, 1588, philosopher +04/08 Buddha born, 563 BC +04/08 David Rittenhouse born, 1732, astronomer & mathematician +04/09 Edward Muybridge born, 1830, motion-picture pioneer +04/09 J. Presper Eckert born, 1919 +04/10 Commodore Matthew Calbraith Perry born, 1854 +04/10 William Booth born, 1829, founder of the Salvation Army +04/13 Thomas Jefferson born, 1743 +04/14 Christian Huygen born, 1629, physicist & astronomer; + discovered Saturn's rings +04/15 Leonardo da Vinci born, 1452 +04/16 Charles (Charlie) Chaplin (Sir) born in London, 1889 +04/22 Kant born, 1724 +04/27 Louis Victor de Broglie born, 1774, physicist +04/28 James Monroe born, 1758 +04/29 Jules Henri Poincare born, 1854, founder of topology +04/29 William Randolph Hearst born in San Francisco, 1863 +04/30 Karl Friedrich Gauss born, 1777, mathematician & astronomer +05/01 Little Walter (Marion Walter Jacobs) is born in Alexandria, + Louisiana, 1930 +05/02 Dr. Benjamin Spock born, 1903 +05/09 Pinza died, 1957 +05/10 Fred Astaire (Frederick Austerlitz) born in Omaha, Nebraska, 1899 +05/11 Johnny Appleseed born, 1768 +05/12 Florence Nightingale born in Florence, Italy, 1820 +05/13 Arthur S. Sullivan born, 1842 +05/15 Mike Oldfield is born in Essex, England, 1953 +05/19 Ho Chi Minh born, 1890 +05/21 Plato (Aristocles) born in Athens(?), 427BC +05/27 Hubert H. Humphrey born, 1911 +05/28 Dionne quintuplets born, 1934 +05/29 Gilbert Keith Chesterton born, 1874 +05/29 John Fitzgerald Kennedy born, 1917 +05/29 Patrick Henry born, 1736 +05/30 Mel (Melvin Jerome) Blanc born in San Francisco, 1908 +06/01 Brigham Young born, 1801 +06/01 Marilyn Monroe born, 1928 +06/02 Edward Elgar (Sir) born in Worcester, England, 1857 +06/03 Henry James born, 1811 +06/07 (Eugene Henri) Paul Gaugin born, 1848 +06/07 George Bryan "Beau" Brummel born, 1778 +06/08 Frank Lloyd Wright born in Richland Center, Wisconsin, 1869 +06/13 Alexander the Great dies (323BC) +06/15 Edward (Edvard Hagerup) Grieg born in Bergen, Norway, 1843 +06/16 Hammurabi the Great dies, Babylon, 1686 bc +06/18 M.C. Escher born, 1898 +06/22 Carl Hubbell born, 1903 +06/22 Meryl Streep born in Summit, New Jersey, 1949 +06/25 Eric Arthur Blair (a.k.a. George Orwell) born, 1903 +06/27 Helen Keller born, 1880 +07/03 Franz Kafka born, 1883 +07/04 Nathaniel Hawthorne born in Salem, Massachusetts, 1804 +07/06 (Helen) Beatrix Potter born, 1866 +07/06 John Paul Jones born, 1747 +07/07 P.T. Barnum dies, 1891 +07/08 Count Ferdinand von Zeppelin born, 1838 +07/10 John Calvin born, 1509 +07/11 John Quincy Adams born, 1767 +07/12 Henry David Thoreau born, 1817 +07/15 Clement Clarke Moore born, 1779, author of "A Visit from + Saint Nicholas" +07/18 Brian Auger is born in London, 1939 +07/25 Steve Goodman is born in Chicago, 1948 +07/29 Mussolini born, 1883 +07/30 Emily Bronte born, 1818 +07/30 Henry Ford born, 1863 +08/01 Herman Melville born, 1819 +08/03 Lenny Bruce dies of a morphine overdose, 1966 +08/08 Dustin Hoffman born in Los Angeles, 1937 +08/13 Annie Oakley born, 1860 +08/13 Fidel Castro born, 1927 +08/17 Mae West born, 1892 +08/18 Meriwether Lewis born, 1927 +08/23 Gene Kelly born, 1912 +08/27 Lyndon B. Johnson born, 1908 +08/29 Oliver Wendell Holmes born, 1809, physician & father of the jurist +08/30 John W. Mauchly born, 1907 +09/05 King Louis XIV of France born, 1638 +09/05 Raquel Welch born, 1942 +09/06 Word is received that Perry has reached the North Pole and died, 1909 +09/07 James Fenimore Cooper born in Burlington, NJ, 1789 +09/07 Queen Elizabeth I of England born, 1533 +09/08 King Richard I of England born, 1157 +09/08 Peter Sellers born in Southsea, England, 1925 +09/09 Chinese Communist Party Chairman Mao Tse-Tung dies at age 82, 1976 +09/12 Jesse Owens born, 1913 +09/13 Walter Reed born, 1851 +09/15 Agatha Christie born in Torquay, England, 1890 +09/16 Allen Funt born in Brooklyn, NY, 1914 +09/18 Greta Garbo born, 1905 +09/18 Jimi Hendrix dies from an overdose, 1970 +09/20 Upton (Beall) Sinclair born, 1878 +09/21 H.G. (Herbert George) Wells born in Bromley, England, 1866 +09/21 Louis Joliet born, 1645 +09/22 President Garfield dies of wounds in Baltimore, 1881 +09/23 Augustus (Gaius Octavius) Caesar born in Rome, 63 BC +09/23 Euripides born in Salamis, Greece, 480 BC +09/24 F. Scott Fitzgerald born, 1896 +09/26 Johnny Appleseed born, 1774 +09/26 T.S. (Thomas Stearns) Eliot born in St. Louis, 1888 +09/27 Thomas Nast born, 1840 +09/28 Michelangelo Buanarroti born in Caprese, Italy, 1573 +09/28 Pompey (Gnaeus Pompeius Magnus) born in Rome, 106BC +09/28 Seymour Cray born, 1925 +09/29 Gene Autry born, 1907 +10/01 Jimmy Carter born, 1924 +10/02 Aristotle dies of indigestion, 322 BC +10/02 Mohandas K. Gandhi born at Porbandar, Kathiawad, India, 1869 +10/04 John V. Atanasoff born, 1903 +10/05 Pablo Picasso born in Malaga, Spain, 1881 +10/05 Ray Kroc (founder of McDonald's) born, 1902 +10/13 Lenny Bruce is born in New York City, 1925 +10/13 Virgil (Publius Vergilius Maro) born near Mantua, Italy, 70 BC +10/14 Dwight David Eisenhower born, 1890 +10/14 William Penn born in London, 1644 +10/15 Pelham Grenville Wodehouse born, 1881 +10/16 Noah Webster born, 1758 +10/16 Oscar (Fingal O'Flahertie Wills) Wilde born in Dublin, 1854 +10/17 Richard Mentor Johnson born, 1780, 9th V.P. of U.S. +10/21 Alfred Nobel born in Stockholm, 1833 +10/27 Gerald M. Weinberg born, 1933 +10/27 James Cook is born, 1466 +10/31 Chiang Kai-Shek born, 1887 +10/31 Dale Evans born, 1912 +11/02 Daniel Boone born near Reading, PA, 1734 +11/04 King William III of Orange born, 1650 +11/05 Roy Rogers born, 1912 +11/09 Carl Sagan born, 1934 +11/10 Martin Luther born in Eisleben, Germany, 1483 +11/10 Soviet President Leonid Brezhnev dies at age 75, 1982 +11/11 Kurt Vonnegut, Jr, born in Indianapolis, 1922 +11/13 Robert Louis Stevenson born, 1850 +11/13 St. Augustine of Hippo born in Numidia, Algeria, 354 +11/18 Imogene Coca born, 1908 +11/18 William S. Gilbert born, 1836 +11/20 RFK born, 1925 +11/26 Charles Schulz born in Minneapolis, 1922 +11/26 Norbert Weiner born, 1894 +11/29 John Mayall is born in Cheshire, England, 1933 +11/30 Cleopatra died, 30 BC +11/30 Mark Twain (Samuel Clemmens) born in Florida, Missouri, 1835 +12/01 Woody Allen (Allen Stuart Konigsberg) born in Brooklyn, NY, 1935 +12/04 Tommy Bolin dies of a heroin overdose in Miami, 1976 +12/05 Walt (Walter Elias) Disney born in Chicago, 1901 +12/08 Horace (Quintus Horatius Flaccus) born in Venosa (Italy), 65BC +12/08 James (Grover) Thurber born in Columbus, Ohio, 1894 +12/10 Emily Dickenson born, 1830 +12/12 E.G. Robinson born, 1893 +12/14 George Washington dies, 1799 +12/17 William Safire (Safir) born, 1929 +12/21 Benjamin Disraeli born, 1804 +12/22 Giacomo Puccini born, 1858 +12/23 Joseph Smith born, 1805 +12/25 Isaac Newton (Sir) born in Grantham, England, 1642 +12/26 Chas. Babbage born, 1791 +12/28 John von Neumann born, 1903 +03/15 J.J. Robert's Birthday in Liberia +03/15 Julius Caesar assassinated by Brutus; Ides of March, 44BC +07/04 John Adams and Thomas Jefferson die on same day, 1826 +07/12 Thoreau's Birthday, 1817 +08/12 Thomas Mann's Death, 1955 +08/20 Leon Trotsky assassinated, 1940 diff --git a/usr.bin/calendar/calendars/calendar.christian b/usr.bin/calendar/calendars/calendar.christian new file mode 100644 index 0000000..7f565d6 --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.christian @@ -0,0 +1,16 @@ +01/06* Epiphany +02/11* Shrove Tuesday / Mardi Gras (day before Ash Wednesday) +02/08* Ash Wednesday (First day of Lent) +03/19* Palm Sunday (7 days before Easter) +03/23* Maundy Thursday (3 days before Easter) +03/24* Good Friday (2 days before Easter) +03/26* Easter Sunday +05/04* Ascension Day (10 days before Pentecost) +05/14* Pentecost (Whitsunday) +05/15* Whitmonday +05/21* Trinity Sunday (7 days after Pentecost) +05/25* Corpus Christi (11 days after Pentecost) +05/28* Rogation Sunday +10/18 Feast Day of St. Luke +12/03* First Sunday of Advent (4th Sunday before Christmas) +12/06 St. Nicholas' Day diff --git a/usr.bin/calendar/calendars/calendar.computer b/usr.bin/calendar/calendars/calendar.computer new file mode 100644 index 0000000..cd0d85d --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.computer @@ -0,0 +1,62 @@ +01/01 AT&T officially divests its local Bell companies, 1984 +01/01 The Epoch (Time 0 for UNIX systems, Midnight GMT, 1970) +01/03 Apple Computer founded, 1977 +01/08 American Telephone and Telegraph loses antitrust case, 1982 +01/08 Herman Hollerith patents first data processing computer, 1889 +01/08 Justice Dept. drops IBM suit, 1982 +01/10 First CDC 1604 delivered to Navy, 1960 +01/16 Set uid bit patent issued, to Dennis Ritchie, 1979 +01/17 Justice Dept. begins IBM anti-trust suit, 1969 (drops it, 01/08/82) +01/24 DG Nova introduced, 1969 +01/25 First U.S. meeting of ALGOL definition committee, 1958 +01/26 EDVAC demonstrated, 1952 +01/31 Hewlett-Packard founded, 1939 +02/11 Last day of JOSS service at RAND Corp., 1966 +02/14 First micro-on-a-chip patented (TI), 1978 +02/15 ENIAC demonstrated, 1946 +03/01 First NPL (later PL/I) report published, 1964 +03/04 First Cray-1 shipped to Los Alamos +03/09 "GOTO considered harmful" (E.J. Dikstra) published in CACM, 1968 +03/14 LISP introduced, 1960 +03/28 DEC announces PDP-11, 1970 +03/31 Eckert-Mauchly Computer Corp. founded, Phila, 1946 +04/01 Yourdon, Inc. founded, 1974 (It figures.) +04/03 IBM 701 introduced, 1953 +04/04 Tandy Corp. acquires Radio Shack, 1963 (9 stores) +04/07 IBM announces System/360, 1964 +04/09 ENIAC Project begun, 1943 +04/28 Zilog Z-80 introduced +05/06 EDSAC demonstrated, 1949 +05/01 First BASIC program run at Dartmouth, 1964 +05/16 First report on SNOBOL distributed (within BTL), 1963 +05/21 DEC announces PDP-8 +05/22 Ethernet first described, 1973 +05/27 First joint meeting of U.S. and European ALGOL definition cte., 1958 +05/28 First meeting of COBOL definition cte. (eventually CODASYL), 1959 +05/30 Colossus Mark II, 1944 +06/02 First issue of Computerworld, 1967 +06/10 First Apple II shipped, 1977 +06/15 UNIVAC I delivered to the Census Bureau, 1951 +06/16 First programming error at Census Bureau, 1951 (apocryphal) +06/23 IBM unbundles software, 1969 +06/23 Turing's Birthday, 1912 +06/30 First advanced degree on computer related topic: to H. Karamanian, + Temple Univ., Phila, 1948, for symbolic diffentiation on the ENIAC +07/08 Bell Telephone Co. formed (predecessor of AT&T), 1877 +07/08 CDC incorporated, 1957 +08/14 First Unix-based mallet created, 1954 +08/14 IBM PC announced, 1981 +08/22 CDC 6600 introduced, 1963 +08/23 DEC founded, 1957 +09/15 ACM founded, 1947 +09/20 Harlan Herrick runs first FORTRAN program, 1954 +10/02 First robotics-based CAM, 1939 +10/06 First GPSS manual published, 1961 +10/08 First VisiCalc prototype, 1978 +10/12 Univac gives contract for SIMULA compiler to Nygaard and Dahl, 1962 +10/14 British Computer Society founded, 1957 +10/15 First FORTRAN Programmer's Reference Manual published +10/20 Zurich ALGOL report published, 1958 +10/25 DEC announces VAX-11/780 +11/04 UNIVAC I program predicts Eisenhower victory based on 7% of votes, 1952 +12/08 First Ph.D. awarded by Computer Science Dept, Univ. of Penna, 1965 diff --git a/usr.bin/calendar/calendars/calendar.history b/usr.bin/calendar/calendars/calendar.history new file mode 100644 index 0000000..9fb2189 --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.history @@ -0,0 +1,486 @@ +01/01 Anniversary of the Triumph of the Revolution in Cuba +01/01 Castro expells Cuban President Batista, 1959 +01/01 Churchill delivers his "Iron Curtain" speech, 1947 +01/01 First Rose Bowl; Michigan 49 - Stanford 0, 1902 +01/04 Quadrantid meteor shower (look north) +01/05 -50 degrees F, Strawberry UT, 1913 +01/05 Fellowship enters Moria (LOTR) +01/05 The FCC hears the first demonstration of FM radio, 1940 +01/05 Twelfth night +01/06 Millard Fillmore's birthday (let's party!) +01/08 Battle of New Orleans +01/09 Fellowship reaches Lorien (LOTR) +01/09 Plough Monday +01/10 First meeting of United Nations General Assembly in London, 1946 +01/10 Thomas Paine's Common Sense published, 1776 +01/11 Anniversary of the Peoples Republic of Albania +01/11 De Hostos' Birthday in Puerto Rico +01/11 Milk delivered in bottles for first time, 1878 +01/11 Prithvi Jayanti in Nepal +01/11 Surgeon General condemned cigarettes, 1964 +01/11 The Whiskey-A-Go-Go opens on Sunset Boulevard in Los Angeles, 1963 +01/14 The first "Be-In" is held in Golden Gate Park, 1967 +01/16 Prohibition begins, 1920 +01/17 Passing of Gandalf (LOTR) +01/18 Grey whale migration, California +01/20 St. Agnes Eve (Ah, bitter chill it was...) +01/24 Eskimo Pie patented by Christian Nelson, 1922 +01/24 Gold discovered in California at Sutter's Mill, 1848 +01/26 Sydney Aust. settled, 1778 +01/27 Grissom, White and Chaffe burned to death in Apollo 1, 1967 +01/27 Vietnam War cease-fire signed, 1973 +01/28 First ski tow, Woodstock VT, 1914 +01/28 Space Shuttle Challenger (51-L) explodes 74 seconds after liftoff + killing Scobee, Smith, McNair, Resnick, Jarvis, Onizuka and McAuliffe, + 1986 +01/30 Mohandas Gandhi assassinated in New Delhi by Hindu fanatic, 1948 +01/30 Tet Offensive, 1968 +01/31 "Ham" the chimpanzee soars into space aboard Mercury-Redstone 2, 1961 +01/31 Explorer I launched, 1958. Van Allen Belt discovered +01/31 Irving Langmuir, 1881, invented tungsten filament lamp +02/01 First TV soap: Secret Storm, 1954 +02/01 Forces lead by Khomeini take over Iran, 1979 +02/04 Cybernet inaugurated, 1969 +02/04 Patricia Hearst kidnapped by Symbionese Liberation Army, 1974 +02/07 Fellowship leaves Lorien (LOTR) +02/08 1963 Revolution Anniversary in Iraq +02/09 -51 degrees F, Vanderbilt MI, 1934 +02/12 Lincoln's real birthday +02/12 Santa Barbara oil leak, 1969 +02/14 Bombing of Dresden, 1945 +02/15 Chicago Seven convicted, 1970 +02/16 Nylon patented, 1937 +02/16 Stephen Decatur burns US frigate in Tripoli, 1804 +02/17 Death of Boromir (LOTR) +02/18 Pluto discovered by Clyde Tombaugh, Lowell Observatory, AZ, 1930 +02/19 US Marines land on Iwo Jima, 1945 +02/20 John Glenn orbits the Earth 3 times, 1962 +02/20 Meriadoc & Pippin meet Treebeard (LOTR) +02/21 Battle of Verdun begins, 1916 1M casualties +02/21 First telephone directory, New Haven, Connecticut, 1878 +02/21 Malcom X shot to death in Harlem, 1965 +02/22 Passing of King Ellesar (LOTR) +02/23 Lt. Calley confesses, implicates Cpt. Medina, 1971 +02/24 Ents destroy Isengard (LOTR) +02/24 Impeachment proceedings against Andrew Johnson begin, 1868 +02/26 Aragorn takes the Paths of the Dead (LOTR) +02/27 The Lionheart crowned, 1189 +02/28 The "French Connection" drug bust occurs in Marseilles, 1972 +02/29 French and Indian raid on Deerfield MA, 1704 +03/01 Sarah Goode, Sarah Osborne, and Tituba arrested for witchcraft + in Salem, Massachusetts, 1692 +03/02 Blackthorn winds (New England) (Does anyone know what this is?) +03/04 First meeting of Congress, 1789, in N.Y.C. +03/05 Frodo & Samwise encounter Shelob (LOTR) +03/06 Hindenburg explodes and burns upon landing at Lakehurst, NJ, 1939 +03/08 Deaths of Denethor & Theoden (LOTR) +03/13 "Striptease" introduced, Paris, 1894 +03/14 Teddy Roosevelt excludes Japanese laborers from continental US, 1907 +03/15 Buzzards return to Hinckley OH +03/15 France assumes protectorate over Vietnam, 1874 +03/15 Watts, Los Angeles, riots kill two, injure 25, 1966 +03/16 First liquid-fuel-powered rocket flight, 1926 +03/16 MyLai Massacre; 300 non-combatant villagers killed by U.S. infantrymen +03/16 Robert Goddard launches first liquid-fueled rocket, Auburn MA, 1926 +03/17 Vanguard I launched, 1958. Earth proved pear-shaped +03/18 Aleksei Leonov performs first spacewalk, 1965 +03/18 Destruction of the Ring (LOTR) +03/19 Swallows return to Capistrano +03/20 Radio Caroline, the original British pirate radio station, sinks, 1980 +03/24 Construction of New York subway system begins, 1900 +03/25 Triangle Shirt Waist Fire, 1911 +03/26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937 +03/27 Khrushchev becomes Premier of Soviet Union, 1958 +03/28 Three Mile Island releases radioactive gas, 1979 +03/29 Flowering of the Mallorn (LOTR) +03/29 Swedish settled Christiana (Wilmington) DE, 1638 +03/30 Alaska purchased from Russia for $7.2 million, 1867 +03/30 Five rings around Uranus discovered, 1977 +03/30 Pencil with eraser patented, 1858 +04/01 People of superb intelligence, savoir-faire, etc. born this day. +04/04 Gandalf visits Bilbo (LOTR) +04/04 Martin Luther King assassinated in Memphis, Tennessee, 1968 +04/04 NATO Established, 1949 +04/06 Joseph Smith founds Mormon Church, 1830 +04/07 Albert Hofmann synthesizes LSD in Switzerland, 1943 +04/07 Alewives run, Cape Cod +04/09 Lee surrenders to Grant at Appomattox Courthouse, 1865 +04/12 Columbia launched, 1981 +04/12 Confederate troops fire first shots of Civil War at Ft Sumter, 1861 +04/12 Space Shuttle Columbia launched, 1981 +04/12 Yuri Gagarin becomes the first man in space, 1961 +04/13 Laotian New Year (3 days) in Laos +04/14 Lincoln shot, 1865 +04/14 Titanic hits iceberg and sinks, 1912 +04/15 Ray Kroc opens first McDonalds in Des Plaines, IL, 1955 +04/16 Lincoln shot in Ford's Theatre by John Wilkes Booth, 1865 +04/17 An unexpected party (LOTR) +04/17 Bay of Pigs invasion crushed by Castro forces, 1961 +04/18 Einstein's Death, 1955 +04/18 First Laundromat opens, Fort Worth Texas, 1934 +04/18 San Francisco earthquake, 1906 +04/19 Landing of the "33" in Uruguay +04/19 Warsaw Ghetto uprising, 1943 +04/20 Supreme Court unanimously rules in favor of busing, 1971 +04/21 Lyrid meteor shower +04/23 Crowning of King Ellesar (LOTR) +04/23 Hank Aaron hits his first home run, 1954 +04/26 William Shakespeare baptised in Stratford-on-Avon, England, 1564, + birthdate unknown +04/27 Magellan killed in Phillippines, 1521 +04/29 Zipper patented by Gideon Sindback, 1913 +05/01 Beltaine; Feast of the god Bel, sun god +05/03 Anti-war protest disrupts business in Washington, 1971 +05/04 Four Kent State students are shot down by the National Guard, 1970 +05/05 John Scopes arrested for teaching evolution, Dayton, TN, 1925 +05/07 Germany surrenders after WWII, 1945 +05/08 Beginning of ostrich mating season +05/08 US institutes mining of Haiphong Harbor, 1972 +05/09 94 degrees, New York, 1979 +05/10 Germany invades Low Countries, 1940 +05/10 Nazi bookburning, 1933 +05/14 Beginning of Lewis and Clark Expedition, 1804 +05/14 Nation of Israel proclaimed, 1948 +05/15 Asylum for Inebriates founded, Binghamton NY, 1854 +05/17 24" rain in 11 hours, Pearl River, S. China, 1982 +05/17 Six SLA members killed in televised gun fight, 1974 +05/18 Battle of Las Piedras in Uruguay +05/18 Napoleon crowned Emperor, 1804 +05/19 Arwen leaves Lorian to wed King Ellesar (LOTR) +05/21 Battle of Iquique in Chile +05/21 US explodes first hydrogen bomb, 1956 +05/22 US Civil War ends, 1865 +05/23 Israeli raid into Argentina to capture Adolf Eichmann, 1960 +05/23 Two Yetis sighted, Mt. Everest, 1953 +05/24 Battle of Pinchincha in Ecuador +05/25 Oral Roberts sees 900 foot tall Jesus Christ, Tulsa OK, 1980 +05/25 Successful test of the limelight in Purfleet, England, 1830 +05/26 Congress sets first immigration quotas, 1924 +05/27 Golden Gate Bridge opens, 1937 +05/29 Edmund Hillary and Tenzing Norkay climb Mt. Everest, 1953 +05/29 First food stamps issued, 1961 +05/30 US Marines sent to Nicaragua, 1912 +06/02 Native Americans "granted" citizenship, 1924 +06/04 Roquefort cheese developed, 1070 +06/05 Robert Kennedy assasinated, 1968 +06/05 US leaves the Gold Standard, 1933 +06/06 First drive-in movie, 1933 +06/06 Normandy landing, 1944 +06/10 Death of Alexander the Great, 323 B.C. +06/10 Denver police tear gas Jethro Tull and 2000 fans at Red Rocks, 1971 +06/11 Greeks seize Troy, 1184BC +06/11 Sauron attacks Osgilliath (LOTR) +06/13 Bilbo returns to Bag End (LOTR) +06/13 Pioneer flies past Neptune, and therefore out of the Solar System +06/14 Sandpaper invented by I. Fischer, Jr., 1834 +06/15 Ben Franklin's kite experiment, 1752 +06/15 Magna Carta signed, 1215 +06/15 Series of photographs by Edward Muggeridge prove to Leland Stanford + that all the hooves of a horse are off the ground during the gallop, + 1878 +06/16 "The Blues Brothers" premieres in Chicago, 1980 +06/17 China explodes its first Hydrogen bomb, 1967 +06/17 Watergate Democratic National Committee break-in, 1972 +06/19 Julius and Ethel Rosenberg are executed in Sing-Sing prison, 1953 +06/19 Lizzie Bordon acquitted, 1893 +06/20 Victoria crowned, 1837 +06/21 Berlin airlift begins, 1948 +06/21 Sun rises over Heelstone at Stonehenge +06/22 Civil rights workers disappear in Mississippi, 1964 +06/23 Slavery abolished in England, 1772 +06/23 Wedding of Ellesar & Arwen (LOTR) +06/24 Senate repeals Gulf of Tonkin resolution, 1970 +06/25 Custer's Last Stand at Little Big Horn, 1876 +06/25 North Korea invades South Korea, 1950 +06/26 Battle of Gettysburg, 1863 +06/26 St. Lawrence Seaway dedicated by Eisenhower & Queen Elizabeth II, 1959 +06/26 Toothbrush invented, 1498 +06/27 100 degrees, Fort Yukon, 1915 +06/27 Bill Graham closes the Fillmore East, 1971 +06/28 Supreme Court decides in favor of Alan Bakke, 1978 +06/30 "That" explosion in Siberia, 1908 +06/30 China and Soviet Union announce split over ideology, 1960 +07/01 Battle of Gettysburg begins, 1863 +07/03 Dog days begin +07/04 Battles of Vicksburg and Gettysburg won by Union forces, 1863 +07/04 Cloudy, 76 degrees, Philadelphia PA, 1776 +07/04 Gandalf imprisoned by Saruman (LOTR) +07/04 New York abstains on Declaration of Independence vote, 1776 +07/04 Thoreau enters woods, 1845 +07/06 First `talkie' (talking motion picture) premiere in New York, 1928 +07/06 Lawrence of Arabia captures Aqaba, 1917 +07/07 First radio broadcast of "Dragnet", 1949 +07/08 First public reading of the Declaration of Independence, 1776 +07/08 Liberty Bell cracks while being rung at funeral of John Marshall, 1835 +07/09 10-hour working day set by law, NH, 1847 +07/10 134 degrees in Death Valley, 1913 +07/12 Minimum wages established: 40 cents/hour, 1933 +07/13 Women first compete in Olympic games, 1908 +07/16 Detonation of the first atomic bomb at Alamagordo, NM, 1945 +07/17 Disneyland opens, 1955 +07/18 Ty Cobb gets 4000th base hit, 1927 +07/19 Five Massachusetts women executed for witchcraft, 1692 +07/20 Armstrong and Aldrin land on moon, 1969 +07/21 First Train Robbery, Jesse James gets $3000 near Adair, Iowa, 1873 +07/21 Vietnam divided at 17th parallel, 1954 +07/23 Ice cream cone introduced, St. Louis MO, 1904 +07/24 Scopes Monkey Trial, 1925 +07/24 The ring comes to Bilbo (LOTR) +07/26 Bilbo rescued from Wargs by Eagles (LOTR) +07/30 "In God We Trust" made U.S. motto, 1956 +07/31 Harry S. Truman dedicates N.Y. Int'l Airport @ Idlewild Field, 1948, + later JFK +08/01 Lughnasa; Feast of the god Lugh, a 30 day Celtic feast centers on + this day +08/03 Columbus sets sail for Cathay, 1492 +08/03 Funeral of King Theoden (LOTR) +08/03 USS Nautilus crosses under north polar ice cap, 1958 +08/04 Axe murder of Andrew and Abbey Borden, 1892 +08/04 Bombing of N. Vietnam begins, 1964 +08/04 Britain declares war on Germany starting World War I, 1914 +08/06 Atomic bomb dropped on Hiroshima, 1945 +08/06 Caricom in Barbados +08/06 Cy Young pitches first game, 1890 +08/08 Atomic bomb dropped on Nagasaki, 1945 +08/08 Montenegro declares war on Germany, 1914 +08/08 Richard Nixon resigns the US presidency, 1974 +08/08 The Great Train Robbery -- $7,368,000, 1963 +08/09 Helter Skelter... the Charles Manson murders take place, 1969 +08/09 Persia defeats Spartan King Leonidas at Thermopylae, 480 BC +08/09 US/Canada border defined in the Webster-Ashburton Treaty, 1842 +08/10 Chicago incorporated as a village of 300 people, 1833 +08/10 US and Panama agree to transfer the canal in the year 2000, 1977 +08/11 Dog days end +08/11 France Ends War in Indochina, 1954 +08/11 Perseid meteor shower (look north; three days) +08/12 First test flight of Space Shuttle "Enterprise" from 747, 1977 +08/12 Last U.S. ground troops out of Vietnam, 1972 +08/13 Berlin wall erected, 1961 +08/13 Li'l Abner debut, 1934 +08/14 Social Security begins in U.S., 1935 +08/15 Gandhi's movement obtains independence for Pakistan and India, 1947 +08/15 Hurricane hits Plimoth Plantation, 1635 +08/16 Roller Coaster patented, 1898 +08/17 First public bath opened in N.Y., 1891 +08/18 Anti-Cigarette League of America formed +08/19 Air Force cargo plane snares payload from Discoverer 14 spy satellite, + marking start of practical military reconnaissance from space, 1960 +08/19 Gail Borden patents condensed milk, 1856 +08/22 Death of King Richard III, 1485, Last of the Plantagenets +08/22 Joe Walker sets X-15 all time altitude mark (67 miles), 1963 +08/22 St. Columbia reports seeing monster in Loch Ness, 565 +08/23 Sacco and Vanzetti executed, 1927 +08/24 "Alice's Restaurant" premieres in New York and Los Angeles, 1969 +08/24 -126.9 F at Vostok, Antarctica, 1960 +08/24 British troops burn Washington, 1814 +08/25 Gen. DeGaulle leads French forces into Paris, 1944 +08/26 Women get the vote, 1920 +08/27 "Tarzan of the Apes" published, 1912 +08/27 Krakatoa, Java explodes with a force of 1,300 megatons, 1883 +08/28 King leads over 200K in civil rights rally in Washington, DC, 1963 +08/29 Star in Cygnus goes nova and becomes 4th brightest in sky, 1975; + Nova Cygni 1975. +08/29 Saruman enters the Shire (LOTR) +08/30 75 cents a pound tariff set on opium, 1842 +08/30 Japan Stationery Co. sells first felt-tipped pen, 1960 +08/30 St. Rose of Lima in Peru +08/30 Washington-to-Moscow hot line connected, 1963 +08/31 269 people killed after Korean Airlines 747 shot down by USSR, 1983 +08/31 Mary Anne Nichols becomes Jack the Ripper's first victim, 1888 +08/31 Non-aggression pact signed by USSR and Afghanistan, 1926 +09/01 Bobby Fischer defeats Boris Spassky in World Chess Match, 1972 +09/01 Joshua A. Norton proclaims himself 'Emperor Norton I', 1859 +09/02 Great Britain adopts Gregorian Calendar, 1752 +09/02 Japan signs unconditional surrender on US battleship `Missouri', 1945 +09/03 Anniversary of the Founding of the Republic in San Marino +09/05 Kennedy orders resumption of underground nuclear tests, 1961 +09/05 The first Continental Congress was convened in Philadelphia, 1774 +09/06 149 Pilgrims set forth from England aboard the Mayflower, 1620 +09/06 First Star Trek episode (The Man Trap) aired 1966 +09/06 Pres. McKinley shot, 1901 +09/06 Somhlolo in Swaziland +09/08 "Star Trek" debuts on NBC (1966) +09/08 Jack the Ripper kills again, Annie Chapman is second victim, 1888 +09/08 President Ford pardons Richard M. Nixon, 1974 +09/09 California becomes the 31st state, 1850 +09/09 United Colonies is renamed the United States, 1776 +09/10 Gandalf escapes from Orthanc (LOTR) +09/10 Mountain Meadows Massacre. Mormons kill Gentile wagon train, 1857 +09/12 German paratroopers rescue Mussolini from captivity in Rome, 1943 +09/12 Germany annexes Sudentenland, 1938 +09/13 136.4 F at el Azizia, Libya, 1922 +09/13 British defeat the French at Abraham near Quebec City, 1788 +09/13 Building of Hadrian's Wall begun, 122 +09/13 Chiang Kai-Shek becomes president of China, 1943 +09/14 Benjamin Franklin is sent to France as an American minister, 1778 +09/14 Frodo & Bilbo's birthday (LOTR) +09/14 Salem, Massachusetts, is founded, 1629 +09/14 The Selective Service Act establishes the first peacetime draft, 1940 +09/15 Black riders enter the Shire (LOTR) +09/15 Soviet Premier Nikita Khrushchev begins his 13 day tour of the US, 1959 +09/15 The U.S. Foreign Affairs Dept. becomes the U.S. State Department, 1789 +09/16 The village of Shawmut, Massachusetts, becomes the city of Boston, 1630 +09/17 Battle of Antietam, 1862 +09/18 Frodo and company rescued by Bombadil (LOTR) +09/18 Victory of Uprona in Burundi +09/20 Equal Rights Party nominates Belva Lockwood for President, 1884 +09/20 First meeting of the American Association for the Advancement of + Science, 1848 +09/20 First meeting of the National Research Council, 1916 +09/20 Magellan leaves Spain on the first Round the World passage, 1519 +09/20 The Roxy Theater opens in Hollywood, 1973 +09/22 Allied forces form the independent nation West Germany, 1953 +09/22 President Lincoln issues the Emancipation Proclamation, 1862 +09/22 Special prosecutor Leon Jeworski subpoenaes President Nixon, 1974 +09/22 The first Soviet atomic bomb explodes, 1949 +09/23 Phillippine President Ferdinand Marcos declares martial law, 1972 +09/23 The New York Knickerbockers becomes the first U.S. Baseball club, 1845 +09/23 V.P. Nixon denies campaign fund fraud with his "Checkers" speech, 1952 +09/25 Sandra Day O'Connor becomes first woman on US Supreme Court, 1981 +09/27 The first passenger was hauled in a locomotive in England, 1825 +09/28 "Pilgrim's Progress" published, 1678 +09/28 A Greek soldier runs 26+ miles after the Persian defeat at Marathon, + 490BC +09/28 Frodo wounded at Weathertop (LOTR) +09/30 Red Jack kills 2, Elizabeth Stride (#3) and Catherine Eddowes (#4), + 1888 +09/30 The first tooth is extracted under anesthesia in Charleston, Mass, 1846 +09/30 The verdicts of the Nuremberg trials are announced, 1946 +10/01 NASA officially begins operations, 1958 +10/02 Thurgood Marshall sworn as the first black Supreme Court Justice, 1967 +10/04 Crimean war begins, 1853 +10/04 First space vehicle, Sputnik I, launched, 1957 +10/04 Sputnik 1, world's first orbiting satellite launched, 1957 +10/05 Frodo crosses bridge of Mitheithel +10/06 Antioch College is the first public school to admit men and women, 1853 +10/06 Egyptian President Anwar Sadat is assassinated in Cairo, 1981 +10/06 Israel is attacked by the alliance of Egypt and Syria, 1973 +10/07 Foundation of the GDR in 1949 in German Democratic Republic +10/07 Georgia Tech. beats Cumberland Univ. 222-0, 1916 +10/07 Maryland Governor Marvin Mandel sent to prison on fraud charges, 1977 +10/07 Mother Teresa of Calcutta awarded the Nobel Peace Prize, 1979 +10/07 Police stop Wilbur Mills car, Fanne Fox jumps into water, 1974 +10/08 Great Chicago Fire, 1871 +10/09 First two-way telephone conversation, 1876 +10/10 Beginning of the Wars for Independence in Cuba +10/10 Foundation of the Workers Party in North Korea +10/10 Mercury at Superior Conjunction with Sun. Moves into night sky. (1984) +10/10 Spiro T. Agnew resigns as Vice-President due to income tax fraud, 1973 +10/11 "Saturday Night Live" premiers on NBC-TV, 1975 +10/11 The Gang of Four are arrested in Peking, 1976 +10/11 The first steam powered ferry ran between New York and Hoboken, 1811 +10/11 The second Vatican Ecumenical Council opens in Rome, 1962 +10/11 First broadcast of Saturday Night Live, 1975 +10/12 Bahama Natives discover Columbus of Europe lost on their shores, 1492 +10/12 Khrushchev pounds his desk with shoe during a speech to the UN, 1960 +10/12 Man O'War's last race, 1920 +10/12 Native Americans discover Columbus of Europe lost on their shores, 1492 +10/13 Italy declares war on Germany, 1943 +10/13 U.S. Navy born, 1775, authorized by the Second Continental Congress +10/14 Battle of Hastings won by William the Conqueror and the Normans, 1066 +10/14 Chuck Yeager breaks sound barrier, 1947 +10/15 First draft card burned, 1965 +10/16 Boromir reaches Rivendell (LOTR) +10/17 Council of Elrond (LOTR) +10/18 Boston Shoemakers form first U.S. labor org., 1648 +10/18 Soviets anounce their probe took photos of the Moon's far side, 1959 +10/19 Mao Tse-tung establishes the People's Republic of China, 1949 +10/19 Napoleon's beaten army begins the long retreat from Moscow, 1812 +10/20 "Saturday Night Massacre", 1973 +10/20 OPEC embargo, 1973 +10/21 Edison makes the first practical incandescent lamp, 1879 +10/21 Guggenheim Museum opens, 1959 +10/23 Battle of Leyte Gulf begins, 1944 +10/23 Earth created at 6:30 AM, 4004BC. +10/23 Swallows leave Capistrano +10/25 End of War of the Ring (LOTR) +10/25 The UN removes Taiwan and admits the People's Republic of China, 1971 +10/26 UN's World Health Organization declares smallpox eradicated, 1978 +10/27 New York's Boss Tweed is arrested on fraud charges, 1871 +10/27 The first New York Subway is opened, 1904 +10/28 Columbus discovers Cuba, 1492 +10/28 Constantine's army defeats forces of Maxentius at Mulvian Bridge, 312 +10/28 Harvard was founded in Massachusetts, 1636 +10/28 Statue of Liberty was dedicated on Bedloe's Island, 1886 +10/29 Stock Market Crash, 1929 +10/30 Orson Welles' "War of the Worlds" broadcast, 1938 +10/31 Luther nails 95 Theses to door of Castle Church, Wittenberg, 1517 +11/01 Austria-Hungary become two seperate nations, 1918 +11/01 Puerto Rican nationalists try to kill Truman at the Blair House, 1950 +11/02 Luftwaffe completes 57 consecutive nights of bombing of London, 1940 +11/02 Two Frenchmen make the first free hot air balloon flight, 1783 +11/03 Beef rises to 3 cents a pound, IL, 1837 +11/03 Linus Pauling wins Nobel Chemistry Prize, 1954 +11/03 Sputnik II launched, 1957, bearing spacedog Laika +11/04 Iranian militants seize US embassy personnel in Teheran, 1979 +11/04 Soviet forces crush the anti-communist revolt in Hungary, 1956 +11/05 Guy Fawkes' Plot, 1605 +11/06 Anniversary of the October Socialist Revolution (2 days) in U.S.S.R. +11/07 Abolitionist newspaperman Elijah P. Lovejoy murdered by mob, 1837 +11/07 Lewis and Clark Expedition in sight of the Pacific Ocean, 1805 +11/09 Blackout of New York, New England, and Eastern Canada, 1965 +11/09 Giant panda discovered (?!), China, 1927 +11/09 Jack the Ripper kills fifth and final victim, Jane Kelly, 1888 +11/09 Margaret Sanger forms American Birth Control League, 1921 +11/09 Roosevelt establishes the Civil Works Administration, 1933 +11/10 41 Women arrested in suffragette demonstartions near White House, 1917 +11/10 Cpt. Wirz, commandant of Andersonville Prison hanged, 1865 +11/10 Henry Stanley asks David Livingston, "Dr. Livingston, I presume?", 1871 +11/11 Washington becomes the 42nd state, 1889 +11/12 Dr. Sun Yat-sen's Birthday in Taiwan +11/12 U.S. first exports oil to Europe, 1861 +11/14 Quarter Pounder price raised from $0.53 to $0.55 in violation of Nixon + price controls (but okayed by Price Commission after formal request + from McDonald's), 1971 +11/15 Niagara Falls power plant startup, 1896 +11/16 Bilbo reaches the Lonely Mountain (LOTR) +11/16 Opening of the Suez Canal, 1869 +11/17 46,000 meteoroids fall over AZ in 20 minutes, 1966 +11/17 Richard Nixon says "I am not a crook.", 1973 +11/18 First hydrogen bomb blasts Enewetok, 1952 +11/18 Local standard time zones established for US, 1883 +11/19 Gettysburg Address delivered, 1863 +11/21 Announcement of 18 1/2 minute gap on Watergate tape, 1973 +11/22 Kennedy shot in Dallas, Texas by Lee Harvey Oswald, 1963 +11/23 First broadcast of Dr. Who (longest running TV series), 1963 +11/24 Lee Harvey Oswald killed by Jack Ruby, 1963 +11/25 Alfred Nobel invents dynamite, 1867 +11/27 Alfred Nobel establishes Nobel Prize, 1895 +11/27 Friction match invented, England, 1826 +11/27 Hoosac Railroad Tunnel completed, 1873, in NW Massachusetts +11/29 King Tut's tomb opened, 1922 +12/01 First national corn-husking championship, Alleman IA, 1924 +12/01 Martin Luther King Jr., leads black boycott of Montgomery buses, 1955 +12/01 Rosa Parks refuses to move to back of the bus (Montgomery, AL), 1953 +12/03 First neon light display, Paris, 1910 +12/03 First successful human heart transplant lead by Dr. Barnard, 1967 +12/03 The Montreux Casino burns down during a Frank Zappa concert, 1971 +12/04 Washington takes leave of his officers at Fraunce's Tavern, NYC, 1783 +12/05 Death of Smaug (LOTR) +12/05 End of Prohibition, 1933 (at least the alcohol part) +12/05 Phi Beta Kappa founded, 1776 +12/05 The Eighteenth Amendment repealed, ending Prohibition, 1933 +12/07 Japan bombs Pearl Harbor, 1941 +12/09 Ball-bearing roller skates patented, 1884 +12/10 Metric system established in France, 1799 +12/10 Nobel Peace Prize awarded each year +12/12 First wireless message sent across Atlantic by Marconi, 1901 +12/13 Apollo 17 leaves the moon, with "last" men to walk on moon aboard, 1972 +12/13 Dartmouth College chartered, 1769 +12/13 Geminid meteor shower (look south) +12/15 Argo Merchant oil spill, 1976 +12/15 Bill of Rights adopted, 1791 +12/15 James Naismith invents basketball, Canada, 1891 +12/15 Sitting Bull shot in head while submitting to arrest, 1890 +12/16 Fellowship begins Quest (LOTR) +12/20 U.S. buys ~1,000,000 sq. miles of Louisiana for ~$20/sq.mi. +12/21 Phileas Fogg completes his trip around the world in less than 80 days +12/24 KKK formed in Pulaski, Tenn, 1865 +12/26 DPMA founded, 1951 +12/27 APT report published, 1956 +12/27 Ether first used as anesthetic in childbirth, 1845 +12/28 Comet Kohoutek at perihelion, 1973 +12/29 Battle of Wounded knee, 1890 +12/30 First Los Angeles freeway dedicated, 1940 +12/31 St. Sylvester in Switzerland +12/31 Winterland closes its doors, 1978 diff --git a/usr.bin/calendar/calendars/calendar.holiday b/usr.bin/calendar/calendars/calendar.holiday new file mode 100644 index 0000000..c39ca41 --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.holiday @@ -0,0 +1,568 @@ +01/01 Independence Day in Haiti, Sudan +01/01 Universal Fraternity Day in Mozambique +01/02 Ancestry Day in Haiti +01/02 St. Berchtold's Day in Switzerland +01/03 New Year's Holiday in Scotland +01/03 Revolution Day in Upper Volta +01/04 Independence Day in Burma +01/04 Martyrs Day in Zaire +01/06 Children's Day in Uruguay +01/06 Three Kings' Day in Puerto Rico +01/07 Christmas in Ethiopia +01/07 Pioneer's Day in Liberia +01/09 Day of the Martyrs in Panama +01/11 Armed Forces Day in Liberia +01/12 Zanzibar Revolution Day in Tanzania +01/13 National Liberation Day in Togo +01/15 Adults Day in Japan +01/15 Arbor Day in Jordan +01/16 Martyrs Day in Benin +01/18 Revolution Day in Tunisia +01/19 Confederate Heroes Day in Texas +01/19 Ethopian Epiphany in Ethiopia +01/19 Nameday of Archbishop Makarios in Cyprus +01/20 Army Day in Mali +01/20 National Heroes Day in Guinea-Bissau +01/20* Lee-Jackson Day in Virginia (3rd Monday) +01/20* Martin Luther King Day in New York (3rd Sunday) +01/20* Robert E. Lee's Birthday in Alabama & Mississippi (3rd Monday) +01/21 Our Lady of Altagracia in Dominican Republic +01/21* Lee-Jackson Day in Virginia (3rd Monday) +01/23 Feast of St. Ildefonsus +01/23 National Handwriting Day +01/24 Economic Liberation Day in Togo +01/26 Republic Day in India +01/30 Australia Day in Australia +02/01 Chinese New Year Holiday (3 days) in Taiwan +02/02 Candlemas +02/04 Independence Commemoration Day in Sri Lanka +02/05 Constitution Day in Mexico +02/06 New Zealand Day +02/07 Independence Day in Grenada +02/09 St. Maron's Day in Lebanon +02/10 Feast of St. Paul's Shipwreck, AD 60 +02/11 National Foundation Day in Japan +02/12 Pyidaungsa Day in Burma +02/16 Makha Bucha Day in Thailand +02/18 Democracy Day in Nepal +02/18 Independence Day in The Gambia +02/23 Republic Day in Guyana +02/24 Gregorian Calendar Day +02/25 National Day in Kuwait +02/27 Independence Day in Dominican Republic +03/01 Samil Independence Movement Day in South Korea +03/01 St. David's Day, Cardiff +03/02 Peasants Day in Burma +03/02 Texas Independence day +03/02 Victory of Adowa in Ethiopia +03/03 Girl's Day in Japan +03/03 Throne Day in Morocco +03/04 Vermont Admission Day (admitted as 14th state in 1791) +03/05 Independence Day in Equatorial Guinea +03/06 Lantern Day, Bejing +03/07* Purim - Feast of Lots +03/08 First Annual International Women's Day, 1909 +03/08 International Women's Day in U.S.S.R. +03/08 Syrian National Day in Libyan Arab Republic +03/08 Women's Day in Guinea-Bissau, Taiwan, Yemen Democratic Republic +03/08 Youth Day in Zambia +03/09 Decoration Day in Liberia +03/09 Falgun Purnima Day in Nepal +03/10 Labor Day in South Korea +03/11 Johnny Appleseed Day; anniversary of the death of John Chapman +03/12 Commonwealth Day in Swaziland +03/12 Independence Day in Mauritius +03/12 Moshoeshoe's Birthday in Lesotho +03/12 Renovation Day in Gabon +03/13 National Day in Grenada +03/16 Black Press Day; first Black newspaper founded in 1827 +03/17 Evacuation Day in Suffolk County, Massachusetts +03/17 St. Patrick's Day +03/19 St. Joseph's Day in Colombia, Costa Rica, Holy See, Liechtenstein, + San Marino, Spain, Venezuela +03/19 Tree Planting Day in Lestho +03/20 Independence Day in Tunsia +03/20 Youth Day in Oklahoma +03/21 Afghan New Year in Afghanistan +03/21 Juarez' Birthday in Mexico +03/22 Abolition Day in Puerto Rico +03/23 Pakistan Day in Pakistan +03/25 Greek Independence Day in Cyprus +03/25 Lady Day (a.k.a. the Feast of the Annunciation) +03/25 Maryland Day in Maryland +03/25 National Holiday in Greece +03/25* Seward's Day in Alaska (last Monday) +03/26 Independence Day in Bangladesh +03/26 Prince Jonah Kuhio Kalanianaole Day in Hawaii +03/27 Armed Forces Day in Burma +03/29 Death of President Barthelemy Boganda in Central African Republic +03/29 Memorial Day in Madagascar +03/31 National Day in Malta +04/01 Youth Day in Benin +04/02 Malvinas Day in Argentina +04/02 Pascua Florida Day in Florida +04/04 Ching Ming Festival in Hong Kong +04/04 Liberation Day in Hungary +04/04 National Day in Senegal +04/05 Arbor Day in South Korea +04/05 Tomb Sweeping Day in Taiwan +04/06 Chakri Memorial Day in Thailand +04/06 Victory Day in Ethiopia +04/08 Fast and Prayer Day in Liberia +04/09 Martyrs Day in Tunisia +04/11 National Heroes Day in Costa Rica +04/13 National Day in Chad +04/13 Songkron Day in Thailand +04/14 Day of the Americas in Honduras +04/15 Bengali New Year in Bangladesh +04/15* Patriot's Day in Maine & Massachusetts (3rd Monday) +04/16 De Diego's Birthday (celebrated in Puerto Rico) +04/16 Holy Week (5 days) in Venezuela +04/16 Tourist Week (5 days) in Uruguay +04/17 Burmese New Year in Burma +04/18 Independence Day in Chile, Zimbabwe +04/19 Declaration of Independence in Venezuela +04/19 Republic Day in Sierra Leone +04/21 San Jacinto Day in Texas +04/22 Arbor Day in Nebraska & Delaware +04/22 Oklahoma Day in Oklahoma +04/24 Victory Day in Togo +04/24* Pesach - First Day of Passover - Festival of Freedom +04/25 Anzac Day in Australia, New Zealand, Tonga, Western Samoa +04/25 Liberation Day in Italy +04/25 National Flag Day in Swaziland +04/26 Confederate Memorial Day in Florida & Georgia +04/26 Union Day in Tanzania +04/27 Independence Day in Togo +04/28* Arbor Day in Wyoming (last Monday) +04/28* Confederate Memorial Day in Alabama & Mississippi (last Monday) +04/30 The Workers Day in Uruguay +05/01 Labor Day in many places +05/01 Law Day (decl. by Eisenhower) +05/01 May Day in many places +05/02 Constitution Day in Japan +05/04 Rhode Island Independence Day +05/05 Children's Day in Japan, South Korea +05/05 Coronation Day in Thailand +05/05 Liberation Day in Netherlands +05/06 Bataan Day in Philippines +05/06* Bank Holiday in UK +05/07 May Day in United Kingdom +05/08 Truman Day in Missouri +05/09 Liberation Day in Czechoslovakia +05/09 Victory Day in Poland, U.S.S.R. +05/10 Confederate Memorial Day in South Carolina +05/10 Mothers Day in Guatamala +05/11 Minnesota Day in Minnesota +05/14 Buddhist Holiday (Waisak 2528) in Indonesia +05/14 Independence Day (2 days) in Paraguay +05/14 Unification Day in Liberia +05/15 Kamuzu Day in Malawi +05/15 Vesak Day in Singapore, Malaysia +05/15 Visakha Bucha Day in Thailand +05/16 Discovery Day in Cayman Islands +05/17 Constitution Day in Nauru, Norway +05/18 Flag Day in Haiti +05/18 Prayer Day in Denmark +05/19 Youth and Sports Day in Turkey +05/19* Memorial Day in Michigan (3rd Monday) +05/20 Mecklenburg Independence Day in North Carolina +05/20 National Day in Cameroon +05/20 Victoria Day in Canada +05/20* Memorial Day in Michigan (3rd Monday) +05/22 National Heroes Day in Sri Lanka +05/23 Commonwealth Day in Jamaica, Belize +05/23 National Labor Day in Jamaica +05/24 Bermuda Day in Bermuda +05/24 Day of Slav Letters in Bulgaria +05/25 African Freedom Day in Zimbabwe +05/25 African Liberation Day in Chad, Mauritania, Zambia +05/25 Independence Day in Jordan +05/25 Memorial Day in New Mexico & Puerto Rico +05/26* First Day of Shavuot +05/27* Bank Holiday in UK +05/28 Mothers Day in Central African Republic +05/31 Pya Martyrs Day in Togo +05/31 Republic Day in South Africa +06/01 Independence Days (3 days) in Western Samoa +06/01 Madaraka Day in Kenya +06/01 Victory Day in Tunisia +06/03 Confederate Memorial Day in Kentucky & Louisiana +06/03 Labor Day in Bahamas +06/03* Bank Holiday in Rep. of Ireland +06/04 Emancipation Day in Tonga +06/05 Constitution Day in Denmark +06/05 Liberation Day in Seychelles +06/06 Memorial Day in South Korea +06/09 Senior Citizen's Day in Oklahoma +06/10 Camoes Day in Portugal +06/11 King Kamehameha I Day in Hawaii +06/12 Independence Day in Philippines +06/14 Flag Day +06/17 Bunker Hill Day in Suffolk County, Massachusetts +06/17 Independence Day in Iceland +06/17 National Day in Federal Republic of Germany +06/18 Evacuation Day in Egypt +06/19 Emancipation Day in Texas +06/19 Labor Day in Trinidad, Tobago +06/19 Revolution Day in Algeria +06/20 Flag Day in Argentina +06/20 West Virginia Day in West Virginia +06/22 National Sovereignty Day in Haiti +06/23 National Holiday in Luxembourg +06/24 Fisherman's Day in Madagascar, Mozambique, Somalia +06/24 Kings Day in Spain +06/24 Peasants Day in Peru +06/24 St. Jean-Baptiste Day in Quebec +06/28 Mothers Day in Central African Republic +06/29 Independence Day in Seychelles +06/29 Last Day of Ramadan* in Algeria, Oman +06/30 Day of the Army in Guatemala +07/01 Dominion Day in Canada +07/01 Freedom Day in Suriname +07/01 Independence Day in Burundi +07/01 National Day in Rwamda +07/01 Republic Day in Ghana +07/02 National Day in Kiribati +07/04 Caribbean Day in Guyana +07/04 Constitution Day in Cayman Islands +07/04 Family Day in Lesotho +07/04 Heroes Day in Zambia +07/04 Kadooment Day in Barbados +07/04 Philippine-American Friendship Day in the Philippines +07/04 Warriors Day (2 days) in Yugoslavia +07/05 Day of Peace and Unity in Rwanda +07/05 Independence Day in Algeria, Venezuela +07/07 National Day in Malawi +07/07 Saba Saba Day in Tanzania +07/09 Independence Day in Argentina +07/10 Independence Day in Bahamas +07/11 National Holiday in the Mongolian People's Republic +07/14 Bastille Day +07/14 National Holiday in Monaco +07/15 St. Swithin's Day +07/16 Presidents Day in Botswanna +07/17 Constitution Day in South Korea +07/17 Public Holiday in Botswanna +07/18 Constitution Day in Uruguay +07/18 Liberation Day in Nicaragua +07/19 Martyrs Day in Burma +07/20 Independence Day in Colombia +07/21 National Holiday in Belgium +07/22 National Day in Poland +07/23 Eqyptian National Day in Syrian Arab Republic +07/23 Remembrance Day in Papua, New Guinea +07/24 Pioneer Day in Utah +07/24 Simon Bolivar's Day in Ecuador, Venezuela +07/25 Constitution Day in Puerto Rico +07/25 National Rebellion Day (3 days) in Cuba +07/25 Republic Day in Tunisia +07/26 Independence Day in Liberia +07/26 National Day in Maldives +07/28 Independence Days (2 days) in Peru +07/29 Rain Day in Waynesburg, PA +07/31 Revolution Day in Congo +08/01 Discovery Day in Trinidad, Tobogo +08/01 Emancipation Day in Granada +08/01 Freedom Day in Guyana +08/01 National Day in Switzerland +08/01 National Holidays (5 days) in El Salvador +08/01 Parent's Day in Zaire +08/03 Independence Day in Jamaica, Niger +08/03 Memorial Day of Archbishop Makarios in Cyprus +08/04 Freedom Day in Guyana +08/05* Bank Holiday in Scotland and Northern Ireland +08/06 Bank Holiday in Australia, British Columbia, Fiji, Iceland, Ireland, + Ontario +08/06 Emancipation Day in Bahamas +08/06 Independence Day in Bolivia +08/09 National Day in Singapore +08/10 Independence Day in Ecuador +08/11 Heroes Day (2 days) in Zimbabwe +08/11 Independence Day in Chad +08/13 Women's Day in Tunisia +08/14 Independence Day in Pakistan +08/14 VJ Day, 1945 +08/15 Independence Day in India +08/15 Liberation Day in South Korea +08/15 National Day in Congo +08/15* Admission Day in Hawaii, 1984 (3rd Friday) +08/16 Bennington Battle Day in Vermont +08/16 Independence Days (3 days) in Gabon +08/16 Restoration Day in Dominican Republic +08/17 Independence Day in Indonesia +08/19 Independence Day in Afghanistan +08/20 Constitution Day in Hungary +08/23 Liberation Days (2 days) in Romania +08/24 National Flag Day in Liberia +08/25 Constitution Day in Paragual +08/25 Independence Day in Uruguay +08/26 Susan B. Anthony Day in Massachussetts +08/26* Bank Holiday in England and Wales +08/27 Liberation Day in Hong Kong +08/28 Heroes Day in Philippines +08/30 Huey P. Long Day in Louisiana +08/30 Victory Day in Turkey +08/31 Independence Day in Trinidad, Tobago +08/31 National Day in Malaysia +08/31 Pashtoonian Day in Afghanistan +09/01 Army Day in Chile +09/03 Independence Day in Qatar +09/03 Memorial Day in Tunisia +09/06 Defense of Pakistan Day in Pakistan +09/06 Settlers Day in South Africa +09/07 Independence Day in Brazil +09/09 Admission Day in California +09/09 National Day in North Korea +09/10 Korean Thanksgiving Day (Chusuk) in South Korea +09/10 National Day in Belize +09/11 National Holiday in Chile +09/12 Defender's Day in Maryland +09/12 Revolution Day in Ethiopia +09/13 Barry Day commemorates the death of Commodore John Barry +09/15 Respect for the Aged Day in Japan +09/16 Cherokee Strip Day in Oklahoma +09/16 Independence Day in Mexico, Papua, New Guinea +09/17 National Heroes Day in Angola +09/18 Independence Day in Chile, Zimbabwe +09/19 Army Day in Chile +09/21 Independence Day in Belize +09/22 Independence Day in Mali +09/22 National Sovereignty Day in Haiti +09/24 Independence Day in Guinea-Bissau +09/24 National Day in Saudi Arabia +09/24 Republic Day in Trinidad, Tobago +09/25 Army Day in Mozambique +09/25 Referendum Day in Rwanda +09/26 National Day in Maldives, Yemem Deomcratic Republic +09/26 Revoluation Anniversary Day in Yemen Arab +09/28 Confucious' Day in Taiwan +09/30 Botswanna Day in Botswanna +09/30 First Day of Sukkot +10/01 Armed Forces Day in South Korea +10/01 Independence Day in Nigeria +10/01 Labor Day in Australia +10/01 National Liberation Day (2 days) in China +10/01 Public Holiday in Botswanna +10/03 National Foundation Day in South Korea +10/03 U.N. Day in Varbados +10/04 Independence Day in Lesotho +10/06 National Sports Day in Lesotho +10/07 National Heroes Day in Jamaica +10/08 Constitution Day in U.S.S.R +10/08 Fiji Day in Fiji +10/08 Thanksgiving Day in Canada +10/09 Independence Day in Uganda +10/09 Korean Alphabet Day in South Korea +10/09 Leif Erikson Day commemorates the discovery of North America in AD 1000 +10/09 Republic Day in Khmer Republic +10/10 Fiji Day in Fiji +10/10 Health-Sports Day in Japan +10/10 National Day in Taiwan +10/10 Oklahoma Historical Day in Oklahoma +10/11 Day of the Revolution in Panama +10/11 Druger Day in South Africa +10/12 Day of the Race in Argentina +10/12 Discovery Day in Gahamas +10/12 National Day in Equatorial Guinea, Spain +10/12 Our Lady Aparecida Day in Brazil +10/12 Pan American Day in Belize +10/13 St. Edward's Day - Patron saint of England +10/14 National Day in Yemen Arab Repyblic +10/14 Young People's Day in Zaire +10/14* Thanksgiving Day in Canada +10/15 Evacuation Day in Tunisia +10/16 National Boss Day +10/17 Heroes Day in Jamaica +10/17 Mother's Day in Malawi +10/20 Kenyatta Day in Kenya +10/21 Armed Forces Day in Honduras +10/21 Revolution Days (2 days) in Somalia +10/23 Chulalongkron's Day in Thsailand +10/24 Independence Day in Zambia +10/24 United Nations Day +10/25 Labor Day in New Zealand +10/25 Taiwan Restoration Day in Taiwan +10/26 Agam Day in Nauru +10/26 Armed Forces Day in Benin, Rwanda +10/26 National Day in Austria +10/28 National Holiday in Greece +10/28 OHI Day in Cyprus +10/28* Bank Holiday in Rep. of Ireland +10/29 Republic Day in Turkey +10/31 Nevada Day in Nevada +11/01 All Saints Day +11/02 All Souls Day in Bolivia, Brazil, El Salvador, Uruguay +11/02 Memorial Day in Ecuador +11/03 Culture Day in Japan +11/03 Thanksgiving Day in Liberia +11/04 Flag Day in Panama +11/04 Will Rogers Day +11/06 Green March Day in Morocco +11/07 National Revolution Day +11/07 October Revolution Day in Hungary +11/11 Independence Day in Angola +11/11 Rememberance Day in Canada +11/11 Republic Day in Maldives +11/15 Dynasty Day in Belgium +11/17 Army Day in Zaire +11/18 Independence Day in Morocco +11/18 National Days (4 days) in Oman +11/19 Discovery Day in Puerto Rico +11/19 Feast Day of S.A.S. Prince Rainier in Monaco +11/20 Revolution Day in Mexico +11/21 Day of Prayer and Repentance in Federal Republic of Germany +11/22 Independence Day in Lebanon +11/23 Labor Thanksgiving Day in Japan +11/25 Independence Day in Suriname +11/28 Independence Day in Albania, Mauritania +11/29 Day of the Republic (2 days) in Yugoslavia +11/29 Goodwill Day in Liberia +11/29 Liberation Day in Albania +11/29 National Day in Burma +11/30 Independence Day in Barbados, Yemen Deomcratic Republic +11/30 National Day in Benin +11/30 National Heroes Day in Philippines +11/30 St. Andrew's Day +12/01 Independence Day in Central African Republic +12/02 National Holiday in United Arab Emirates +12/03 National Holiday in Laos +12/06 Independence Day in Finland +12/07 Delaware Day in Delaware +12/07 Independence Day in Ivory Coast, Panama +12/08 Mother's Day in Panama +12/09 Independence Day in Tanzania +12/10 Human Rights Day +12/10 Thai Constitution Day in Thailand +12/10 Wyoming Day in Wyoming +12/11 Independence Day in Upper Volta +12/12 Independence Day in Kenya +12/13 Republic Day in Malta +12/15 Statue Day in Netherlands Antilles +12/16 Constitution Day in Nepal +12/16 Day of the Covenant in South Africa +12/16 National Day in Bahrain +12/16 Victry Day in Bangladesh +12/17 National Day in Bhutan +12/18 Republic Day in Niger +12/23 Victory Day in Egypt +12/25 Children's Day in Congo +12/26 Bank Holiday in Canada, Rep. of Ireland, and UK +12/26 Boxing Day +12/26 Family Day in South Africa +12/26 St. Stephen's Day +12/26 Bank Holiday in Canada, Rep. of Ireland, and UK +12/27 Bank Holiday in Cayman Islands +12/27 Constitution Day in North Korea +12/27 Public Holiday in Lesotho, Zimbabwe +12/29 Civic Holidays (3 days) in Costa Rica +12/31 Bank Holiday in El Salvador, Honduras, Pakistan +12/31 Feed Yourself Day in Benin + +04/21 Tiradentes in Brazil +04/25 Anniversary of the Revolution in Portugal +04/29 Emperor's Birthday in Japan +04/30 Queen's Birthday in Netherlands, Netherlands Antilles +05/01 Boy's day in Japan +05/02 King's Birthday in Lesotho +05/05 Battle of Puebla in Mexico +05/08 Buddha's Birthday in South Korea +05/08 Elections for the National Assembly in Philippines +05/14 Anniversary of the Founding of Guinean Deomcratic Party in Guinea + +05/25 Anniversary of the Revolution of 1810 in Argentina +05/25 Revolution in the Sudan in Libyan Arab Republic +05/27 Afghanistan attains sovereignty, 1921 +06/02 Corpus Christi in Paraguay +06/03 Jefferson Davis's Birthday in Alabama & Mississippi (1st Monday) +06/03 Jefferson Davis's Birthday in Florida, Georgia, & S. Carolina +06/04 Queen's Birthday in New Zealand +06/06 His Majesty, Yang Di-Pertuan Agong's Birthday in Malaysia +06/11 Queen's Birthday +06/12 Peace with Bolivia in Paraguay +06/13 Corrective Movement in Yemen Arab Republic +06/16 Bloomsday - Anniversary of Dublin events, 1904, in "Ulysses" +06/18 Queen's Birthday in Fiji +06/19 Artigas Birthday in Uruguay +06/22 Corrective Movement in Yermen Democratic Republic +06/22 Midsummer Eve in Finland, Sweden +06/24 Battle of Carabobob in Venezuela +07/01 Eid-Ul-Fitr* (2 days) in Pakistan +07/01 Union of the Somalia Republic in Somalia +07/07 Anniversary of the P.U.N. in Equatorial Guinea +07/12 Battle of Boyne celebrated in Northern Ireland +07/12 The Twelfth in Northern Ireland +07/13 Buddhist Lent in Thailand +07/14 Anniversary of the Revolution in Iraq +07/17 July Revolution in Iraq +07/17 Munoz Rivera's Birthday (celebrated in Puerto Rico) +07/22 King's Birthday in Swaziland +07/23 Anniversary of the Revolution in Egypt +07/25 St. James, Patron Saint in Spain +07/27 Barbosa's Birthday (celebrated in Puerto Rico) +07/29 Olsok Eve in Norway to commemorate Norway's Viking King St. Olav +08/01 Founding of Asuncion in Paraguay +08/02 Our Lady of Los Angeles in Costa Rica +08/03 Massacre du Pidjiguiti in Buinea-bissau +08/07 Battle of Boyaca in Colombia +08/11 King Hussein's Accession to the Throne in Jordan +08/12 Queen's Birthday in Thailand +08/13 Proclamation of Independence in Central African Republic +08/14 Waddi Dhahab in Morocco +08/15 Founding of Ascuncion in Paraguay +08/15 Santa Maria in Malta +08/17 Anniversary of the Death of General San Martin in Argentina +09/09 Anniversary of the Socialist Revolution (2 days) in Bulgaria +09/10 Moon Festival in Taiwan +09/11 Aniversary of military coup in Chile +09/11 Ethiopian New Year in Ethiopia +09/12 Amilcar Cabral's Birthday in Guinea-Bissau +09/14 Battle of San Jacinto in Nicaragua +09/15 Foundation of Panama in Panama +09/23 Grito de Lares in Puerto Rico +09/24 Anniversary of the Third Republic in Ghana +09/24 Our Lady of Mercedes in Dominican Republic +09/27 Feast of Finding the True Cross in Ethiopia +09/29 Battle of Boqueron in Paraquay +10/02 Anniversary of Guinean Independence in Guinea +10/03 Chung Yeung Festival in Hong Kong +10/03 Francisco Morazan's Birthday in Honduras +10/05 Anniversary of Proclamation of the Republic in Portugal +10/08 Battle of Agamos in Peru +10/09 Independence of Guayaquil in Ecuador +10/17 Dessaline's Death Anniversary in Haiti +10/20 Anniversary of the 1944 Revolution in Guatemala +11/01 Feast of All Saints in Portugal +11/01 Samhain; Beginning of the Celtic year and most important holiday. +11/03 Independence from Columbia in Panama +11/03 Independence of Cuenca in Ecuador +11/06 Prophet Mohammed's Birthday in Malaysia +11/07 Anniversary of Great October Revolution in Bulgaria +11/08 Her Majesty, the Queen's Birthday in Nepal +11/10 King's Birthday in Bhutan +11/11 Angola gains independence from Portugal, 1975 +11/11 Independence of Cartagena in Colombia +11/12 Prince Charles' Birthday in Fiji +11/14 King Hussein's Birthday in Jordan +11/15 Proclamation of the Republic in Brazil +11/15 Thatlouang Festival in Laos +11/16 Oklahoma Heritage Week in Oklahoma +11/17 Corrective Movement in Syrian Arab Republic +11/18 Battle of Viertieres in Haiti +11/19 Anniversary of the 1968 Coup by the Army in Mali +11/19 Garifuna Settlement in Belize +11/19 Prince of Wales Birthday in Fiji +11/22 Anniversary of Portuguese Aggression in Guinea +11/24 Anniversary of the New Regime in Zaire +11/28 Independence from Spain in Panama +11/28 Proclamation of the Republic in Chad +12/01 Anniversary of the Restoration of Independence in Portugal +12/07 Prophet Mohammed's Birthday in Fiji +12/08 Blessing of the Water in Uruguay +12/08 Our Lady of the Cacupe in Paraguay +12/10 Foundation of Worker's Party in Angola +12/25 Birthday of Quaid-i-Azam in Pakistan +12/26 Feast of Our Theotokos in Greece +12/29 His Majesty, the King's Birthday in Nepal +12/30 Anniversary of the Democratic Republic of Madagascar in Madagascar +12/31 Proclamation of the Republic in Congo diff --git a/usr.bin/calendar/calendars/calendar.judaic b/usr.bin/calendar/calendars/calendar.judaic new file mode 100644 index 0000000..df39ad5 --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.judaic @@ -0,0 +1,30 @@ +03/08* Fast of Esther (Battle of Purim; 1 day before Purim; fast day) +03/11* Purim (Feast of Lots; 30 days before Pesach) +03/12* Purim (Feast of Lots) +04/10* Pesach (First Day of Passover; sabbatical) +04/11* Pesach (sabbatical) +04/16* Pesach (sabbatical) +04/17* Pesach (Last Day of Passover; 8th day of Pesach; sabbatical) +04/30* Yom HaAtzmaut (Israel Independence Day) +05/13* Lag Ba`omer (Commemoration of the Great Rebellion) +05/22* Yom Yerushalayim (Reunification of Jerusalem) +05/30* Shavuos (Festival of Weeks; 50 days after Pesach; sabbatical) +05/31* Shavuos (Festival of Weeks; sabbatical) +07/10* Fast of Shiv'a Asar B'Tammuz (Romans breach Wall of Jerusalem; + fast day) +07/31* Fast of Tish'a B'Av (Babylon/Rome destroys Holy Temple; fast day) +09/20* First Day of Rosh Hashanah (Jewish Lunar New Year; 5741 == 1980; + sabbatical) +09/21* Rosh Hashanah (sabbatical) +09/23* Fast of Gedalya (Murder of Gedalya and subsequent Exile; 1 day + after Rosh Hashanah; fast day) +09/29* Yom Kippur (Day of Atonement; 9 days after Rosh Hashanah; + sabbatical, fast day) +10/04* Succos (Festival of Tabernacles; 14 days after Rosh Hashanah; + sabbatical) +10/05* Succos (sabbatical) +10/10* Hoshanah Rabba (7th day of Succos) +10/11* Shmini Atzeres (8th Day of Gathering; 1 day after Succos; sabbatical) +10/12* Shmini Atzeres/Simchas Torah (Rejoicing of the Law; sabbatical) +12/12* First Day of Chanukah +12/27* Fast of Asara B'Tevet (Babylonians put siege on Jerusalem; fast day) diff --git a/usr.bin/calendar/calendars/calendar.music b/usr.bin/calendar/calendars/calendar.music new file mode 100644 index 0000000..8609e3f --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.music @@ -0,0 +1,178 @@ +01/01 Country Joe McDonald is born in El Monte, California, 1942 +01/03 Steven Stills is born in Dallas, 1945 +01/04 Jazz great Charlie Mingus dies at 57 in Cuernavaca, Mexico, 1979 +01/08 David Bowie (then David Robert Jones) is born in London, 1947 +01/09 James Patrick Page (Led Zeppelin) is born in Middlesex, England, 1945 +01/10 Blues guitarist Howlin' Wolf dies in Chicago, 1976 +01/10 Jim Croce is born in Phildelphia, 1943 +01/10 Pat Benatar is born in Long Island, 1952 +01/10 Rod Stewart is born in Glasgow, Scotland, 1945 +01/13 Eric Clapton plays the "Rainbow Concert" in London, 1973 +01/17 Led Zeppelin's first album is released, 1969 +01/19 Janis Joplin is born in Port Arthur, Texas, 1943 +01/22 Sam Cooke is born in Chicago, 1935 +01/24 Warren Zevon is born, 1947 +01/25 Bob Dylan plays the second "Hurricane" benefit, in the Astrodome, 1978 +01/27 Bobby "Blue" Bland (Robert Calvin Bland) is born in Tennessee, 1930 +01/27 Wolfgang Amadeus Mozart born in Salzburg, 1756 +01/28 Jimi Hendrix headlines Madison Square Garden, 1970 +01/30 Lightnin' Hopkins, the most-recorded blues artist ever, dies, 1982 +01/31 The Grateful Dead are busted in New Orleans, 1970 +02/01 RCA Victor unveils the 45 rpm record playing system, 1949 +02/02 Graham Nash is born in Lancashire, England, 1942 +02/03 The Day The Music Died; Buddy Holly, Richie Valens, and the Big + Bopper are killed in a plane crash outside Mason City, Iowa, 1959 +02/07 Beatles land at JFK airport to begin first U.S. tour, 1964 +02/07 Steven Stills makes the first digitally recorded rock album, 1979 +02/09 Carole King (Carole Klein) is born in Brooklyn, 1941 +02/12 The Beatles play Carnegie Hall in New York City, 1964 +02/17 Jazz great Thelonius Monk dies in Englewood, New Jersey, 1982 +02/18 Yoko Ono Lennon is born in Tokyo, 1933 +02/19 Paul McCartney's "Give Ireland Back to the Irish" is banned in + Britain, 1972 +02/19 William "Smokey" Robinson is born in Detroit, 1940 +02/20 J. Geils (J. Geils Band) is born, 1946 +02/20 Yes sells out Madison Square Garden...without advertising, 1974 +02/23 Handel born, 1685 +02/23 Johnny Winter is born in Leland, Mississippi, 1944 +02/29 Jimmy Dorsey born, 1904 +03/01 Jim Morrison is busted for obscenity in Miami, 1969 +03/02 Blues guitarist Rory Gallagher is born in Ballyshannon, Ireland, 1949 +03/03 Buffalo Springfield is formed in Los Angeles, 1966 +03/04 Antonio Vivaldi born in Venice, Italy, 1678 +03/07 Last Gilbert & Sullivan opera produced, 1896 +03/08 Ron "Pigpen" McKernan (Grateful Dead) dies in California, 1973 +03/09 Robin Trower is born in London, 1945 +03/13 The Allman Brothers record their live album at the Fillmore East, 1971 +03/15 Sly Stone born, 1944 +03/17 Paul Kantner (Jefferson Airplane) is born in San Francisco, 1942 +03/21 J.S. Bach born, 1685 +03/22 Ten Years After plays their last concert, 1974 +03/25 Aretha Franklin is born in Detroit, 1943 +03/26 Emerson, Lake, and Palmer record "Pictures at an Exhibition" live, 1971 +03/29 Dr. Hook gets a group picture on the cover of "Rolling Stone", 1973 +03/30 Eric Clapton is born in Surrey, England, 1945 +04/02 Marvin Gaye is born in Washington, D.C., 1939 +04/04 Muddy Waters (McKinley Morganfield) is born in Rolling Fork, + Mississippi, 1915 +04/09 Paul Robeson born, 1898 +04/10 Paul McCartney announces that he's quitting the Beatles, 1970 +04/14 Ritchie Blackmore (Deep Purple, Rainbow) is born, 1945 +04/18 Yes breaks up after 13 years, 1981 +04/25 Blues guitarist Albert King is born, 1925 +04/25 Ella Fitzgerald born, 1918 +04/26 Carol Burnett born in San Antonio, Texas, 1933 +04/29 "Hair" premiers on Broadway, 1968 +05/01 Kate Smith born, 1909 +05/03 Bob Seger is born in Ann Arbor, Michigan, 1945 +05/07 Johannes Brahms born in Hamburg, 1833 +05/07 Tchaikowsky born, 1840 +05/10 Dave Mason is born in Worcester, England, 1945 +05/11 Bob Marley dies in his sleep in Miami, 1981 +05/12 Pink Floyd performs the first quadrophonic concert, 1977 +05/18 Rick Wakeman is born in West London, England, 1949 +05/19 Pete Townshend is born in London, 1945 +05/20 The Jimi Hendrix Experience is signed by Reprise Records, 1967 +05/22 Johann Sebastian Bach born in Eisenach, Germany, 1665 +05/23 Blues great Elmore James dies, 1963 +05/24 Bob Dylan (Robert Zimmerman) is born in Duluth, 1941 +05/26 Al Jolson born, 1886 +05/31 The Who perform the loudest concert ever -- 76,000 watts of PA, 1976 +06/01 The Beatles release "Sgt. Pepper", 1967 +06/06 "Rock Around The Clock" makes Billboard's #1 slot, 1955 +06/07 Blind Faith debuts in concert at London's Hyde Park, 1969 +06/09 Les Paul (Lester Polfus) is born in Waukesha, Wisconsin, 1923 +06/10 Howlin' Wolf (Chester Burnett) is born in West Point, Mississippi, 1910 +06/10 Judy Garlnad born, 1922 +06/15 Harry Nilsson is born in Brooklyn, 1941 +06/16 The Monterey Pop festival opens, 1967 +06/18 Paul McCartney born in Liverpool, England, 1942 +06/21 Columbia records announces the first mass production of LP's, 1948 +06/22 Todd Rundgren is born in Upper Darby, Pennsylvania, 1948 +06/24 Jeff Beck is born in Surrey, England, 1944 +07/02 Felix Pappalardi and Leslie West form Mountain, 1969 +07/03 Jim Morrison dies in Paris, 1971 +07/06 The Jefferson Airplane is formed in San Francisco, 1965 +07/07 Ringo Starr (Richard Starkey) born in Liverpool, England, 1940 +07/12 Chicago DJ Steve Dahl holds "Disco Demolition" at Kamisky Park, 1979 +07/14 Woodie Guthrie born, 1912 +07/16 Cream forms in the U.K., 1966 +07/16 Harry Chapin dies on Long Island Expressway, 1981 +07/17 "Yellow Submarine" premieres at the London Pavilon, 1968 +07/20 Carlos Santana is born in Autlan, Mexico, 1947 +07/25 Bob Dylan goes electric at the Newport Folk Festival, 1965 +07/25 Crosby, Stills, Nash & Young debut at the Fillmore East, 1969 +07/26 Mick Jagger is born in Kent, England, 1943 +07/28 Bach dies, 1750 +07/28 The Watkins Glen "Summer Jam" opens, 1973 +08/01 The Concert for Bangla Desh takes place at Madison Square Garden, 1971 +08/04 John Lennon points out that "the Beatles are more popular than Jesus", + 1966 +08/10 Ian Anderson (Jethro Tull) is born in Edinburgh, Scotland, 1947 +08/13 Dan Fogelberg is born in Peoria, Illinois, 1951 +08/15 Beatles replace drummer Pete Best with Richard Starkey +08/15 The Beatles play Shea Stadium in New York, 1965 +08/15 Woodstock Festival, Max Yasgur's farm, 1969 +08/26 Jimi Hendrix gives his last performance at the Isle of Wight, 1970 +08/26 Jimi Hendrix's Electric Ladyland Studios opens in New York, 1970 +09/07 Keith Moon (The Who) dies in London of a drug overdose, 1978 +09/08 Anton Dvorak born in Nelahozeves, Czechoslovakia, 1841 +09/08 Ron "Pigpen" McKernan (Grateful Dead) is born in San Bruno, + California, 1945 +09/14 Francis Scott Key writes words to "Star Spangled Banner", 1814 +09/16 B.B. King is born in Itta Bena, Mississippi, 1925 +09/19 Simon & Garfunkel reunite to play New York's Central Park, 1981 +09/20 Jim Croce dies in a plane crash, 1973 +09/23 "Paul is dead" rumors sweep the country, 1969 +09/23 Bruce "The Boss" Springsteen is born in Freehold, New Jersey, 1949 +09/25 John Bonham (Led Zeppelin) dies of alcohol poisoning, 1980 +09/26 George Gershwin born in Brooklyn, NY +10/04 Janis Joplin O.D.s, 1970 +10/04 Janis Joplin dies of a heroin overdose in Hollywood, 1970 +10/05 Steve Miller is born in Dallas, 1943 +10/07 First Bandstand (later, American Bandstand) broadcast, 1957 +10/09 John Lennon born in Liverpool, England, 1940 +10/10 John Prine is born in Maywood, Illinois, 1946 +10/12 The Jimi Hendrix Experience is formed in London, 1966 +10/16 Bob Weir (Grateful Dead) is born in San Francisco, 1947 +10/17 "Hair" opens at New York's Public Theater, 1967 +10/18 Chuck Berry is born in San Jose, California, 1926 +10/20 Three members of Lynyrd Skynyrd die in a plane crash, 1977 +10/22 Franz Liszt born, 1811 +10/25 Jon Anderson (Yes) is born in Lancashire, England, 1944 +10/25 The Rolling Stones appear on The Ed Sullivan Show, 1964 +10/29 Duane Allman dies in motorcycle crash near Macon, Georgia, 1971 +10/30 Grace Slick is born in Chicago, 1939 +11/02 Jimi Hendrix's "Electric Ladyland" enters US charts at #1, 1968 +11/02 Keith Emerson is born, 1944 +11/03 James Taylor and Carly Simon are married in Manhattan, 1972 +11/07 Joni Mitchell (Roberta Joan Anderson) is born in Alberta, Canada, 1943 +11/08 Patti Page born, 1927 +11/09 The first issue of "Rolling Stone" is published, 1967 +11/10 Greg Lake is born in Bournemouth, England, 1948 +11/12 Neil Young is born in Toronto, 1945 +11/13 Paul Simon born, 1942 +11/16 Bill Ham first demonstrates his psychedelic "Light Show", 1965 +11/20 Duane Allman is born in Nashville, Tennessee, 1946 +11/20 Joe Walsh is born in Cleveland, 1947 +11/24 Scott Joplin born, 1868 +11/25 "The Last Waltz" concert is played by The Band at Winterland, 1976 +11/25 Johann Strauss, Jr., writes `On the Beautiful Blue Danube', 1867 +11/26 Cream performs their farewell concert at Royal Albert Hall, 1968 +11/27 Jimi Hendrix (Johnny Allen Hendrix) is born in Seattle, 1942 +12/05 Mozart dies, 1791 +12/06 First sound recording made by Thomas Edison, 1877 +12/06 The Rolling Stones play Altamont Speedway near San Francisco, 1969 +12/07 Harry Chapin is born in New York City, 1942 +12/08 Jim Morrison is born in Melbourne, Florida, 1943 +12/08 John Lennon is shot and killed in New York City, 1980 +12/09 The Who's "Tommy" premieres in London, 1973 +12/13 Ted Nugent, the motor city madman, born in Detroit, 1949 +12/15 Thomas Edison receives patent on the phonograph, 1877 +12/16 Beethoven born, 1770 +12/16 Don McLean's "American Pie" is released, 1971 +12/16 Ludwig von Beethoven christened in Bonn, Germany, 1770 +12/21 Frank Zappa is born in Baltimore, 1940 +12/23 First G&S collaboration, Thespis, 1871 +12/28 Edgar Winter is born in Beaumont, Texas, 1946 +12/31 Jimi Hendrix introduces the Band of Gypsies at the Fillmore East, 1969 diff --git a/usr.bin/calendar/calendars/calendar.usholiday b/usr.bin/calendar/calendars/calendar.usholiday new file mode 100644 index 0000000..f799d0b --- /dev/null +++ b/usr.bin/calendar/calendars/calendar.usholiday @@ -0,0 +1,31 @@ +01/01 New Year's Day +01/14 Julian Calendar New Year's Day +02/02 Groundhog Day +02/14 St. Valentine's Day +02/20* President's Day (3rd Monday of February) +03/05 Mother-in-Law Day +03/17 St. Patrick's Day +03/20* Vernal Equinox +04/01 April Fool's Day +04/15 Income Tax Day +04/03* Daylight Savings Time begins; clocks move forward (1st Sunday of April) +04/28* Arbor Day (varies from state to state) +05/14* Mother's Day (2nd Sunday of May) +05/20* Armed Forces Day (3rd Saturday of May) +05/29* Memorial Day (Last Monday of May) +06/18* Father's Day (3rd Sunday of June) +06/21* Summer Solstice +07/04 Independence Day +09/04* Labor Day (1st Monday of September) +09/09* Grandparent's Day (2nd Sunday of September; varies from state to state) +09/22* Autumnal Equinox +10/09* Columbus Day (2nd Monday of October) +10/29* Daylight Savings Time ends; clocks move back (Last Sunday in October) +10/31 All Hallows Eve (Halloween) +11/06* Election Day (1st Tuesday after 1st Monday for even years) +11/11 Veterans' Day +11/29 Thanksgiving Day (Last Thursday in November) +12/21* Winter Solstice +12/24 Christmas Eve +12/25 Christmas +12/31 New Year's Eve diff --git a/usr.bin/calendar/pathnames.h b/usr.bin/calendar/pathnames.h new file mode 100644 index 0000000..8a0838c --- /dev/null +++ b/usr.bin/calendar/pathnames.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_CPP "/usr/bin/cpp" + /* XXX -- fix when cpp parses arguments rationally */ +#define _PATH_INCLUDE "-I/usr/share/calendar" diff --git a/usr.bin/cap_mkdb/Makefile b/usr.bin/cap_mkdb/Makefile new file mode 100644 index 0000000..0e403af --- /dev/null +++ b/usr.bin/cap_mkdb/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= cap_mkdb + +.include diff --git a/usr.bin/cap_mkdb/cap_mkdb.1 b/usr.bin/cap_mkdb/cap_mkdb.1 new file mode 100644 index 0000000..b2a3900 --- /dev/null +++ b/usr.bin/cap_mkdb/cap_mkdb.1 @@ -0,0 +1,101 @@ +.\" 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. +.\" +.\" @(#)cap_mkdb.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 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 0000000..f809c86 --- /dev/null +++ b/usr.bin/cap_mkdb/cap_mkdb.c @@ -0,0 +1,250 @@ +/*- + * 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 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[] = "@(#)cap_mkdb.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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/checknr/Makefile b/usr.bin/checknr/Makefile new file mode 100644 index 0000000..c265248 --- /dev/null +++ b/usr.bin/checknr/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= checknr + +.include diff --git a/usr.bin/checknr/checknr.1 b/usr.bin/checknr/checknr.1 new file mode 100644 index 0000000..1a49c5f --- /dev/null +++ b/usr.bin/checknr/checknr.1 @@ -0,0 +1,159 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)checknr.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt CHECKNR 1 +.Os BSD 4 +.Sh NAME +.Nm checknr +.Nd check nroff/troff files +.Sh SYNOPSIS +.Nm checknr +.Op Fl a Ns Ar \&.x1.y1.x2.y2. ... \&.xn.yn +.Op Fl c Ns Ar \&.x1.x2.x3 ... \&.xn +.Op Fl s +.Op Fl f +.Ar file +.Sh DESCRIPTION +.Nm Checknr +checks a list of +.Xr nroff 1 +or +.Xr troff 1 +input files for certain kinds of errors +involving mismatched opening and closing delimiters +and unknown commands. +If no files are specified, +.Nm checknr +checks the standard input. +.Pp +Options: +.Bl -tag -width Ds +.It Fl a +Add additional pairs of macros to the list of known macros. +This must be followed by groups of six characters, each group defining +a pair of macros. +The six characters are +a period, +the first macro name, +another period, +and the second macro name. +For example, to define a pair .BS and .ES, use +.Sq Li \-a.BS.ES +.It Fl c +Define commands which would otherwise be complained about +as undefined. +.It Fl f +Request +.Nm checknr +to ignore +.Ql \ef +font changes. +.It Fl s +Ignore +.Ql \es +size changes. +.El +.Pp +Delimiters checked are: +.Bl -enum +.It +Font changes using \efx ... \efP. +.It +Size changes using \esx ... \es0. +.It +Macros that come in open ... close forms, for example, +the .TS and .TE macros which must always come in pairs. +.El +.Pp +.Nm Checknr +is intended for use on documents that are prepared with +.Nm checknr +in mind, much the same as +.Xr lint 1 . +It expects a certain document writing style for +.Ql \ef +and +.Ql \es +commands, +in that each +.Ql \efx +must be terminated with +.Ql \efP +and +each +.Ql \esx +must be terminated with +.Ql \es0 . +While it will work to directly go into the next font or explicitly +specify the original font or point size, +and many existing documents actually do this, +such a practice will produce complaints from +.Nm checknr . +Since it is probably better to use the +.Ql \efP +and +.Ql \es0 +forms anyway, +you should think of this as a contribution to your document +preparation style. +.Pp +.Nm Checknr +knows about the +.Xr ms 7 +and +.Xr me 7 +macro packages. +.Sh SEE ALSO +.Xr nroff 1 , +.Xr troff 1 , +.Xr checkeq 1 , +.Xr ms 7 , +.Xr me 7 +.Sh DIAGNOSTICS +.Bd -ragged -compact +Complaints about unmatched delimiters. +Complaints about unrecognized commands. +Various complaints about the syntax of commands. +.Ed +.Sh BUGS +There is no way to define a 1 character macro name using +.Fl a . +.Pp +Does not correctly recognize certain reasonable constructs, +such as conditionals. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/checknr/checknr.c b/usr.bin/checknr/checknr.c new file mode 100644 index 0000000..774d3b0 --- /dev/null +++ b/usr.bin/checknr/checknr.c @@ -0,0 +1,586 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)checknr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * checknr: check an nroff/troff input file for matching macro calls. + * we also attempt to match size and font changes, but only the embedded + * kind. These must end in \s0 and \fP resp. Maybe more sophistication + * later but for now think of these restrictions as contributions to + * structured typesetting. + */ +#include +#include + +#define MAXSTK 100 /* Stack size */ +#define MAXBR 100 /* Max number of bracket pairs known */ +#define MAXCMDS 500 /* Max number of commands known */ + +/* + * The stack on which we remember what we've seen so far. + */ +struct stkstr { + int opno; /* number of opening bracket */ + int pl; /* '+', '-', ' ' for \s, 1 for \f, 0 for .ft */ + int parm; /* parm to size, font, etc */ + int lno; /* line number the thing came in in */ +} stk[MAXSTK]; +int stktop; + +/* + * The kinds of opening and closing brackets. + */ +struct brstr { + char *opbr; + char *clbr; +} br[MAXBR] = { + /* A few bare bones troff commands */ +#define SZ 0 + "sz", "sz", /* also \s */ +#define FT 1 + "ft", "ft", /* also \f */ + /* the -mm package */ + "AL", "LE", + "AS", "AE", + "BL", "LE", + "BS", "BE", + "DF", "DE", + "DL", "LE", + "DS", "DE", + "FS", "FE", + "ML", "LE", + "NS", "NE", + "RL", "LE", + "VL", "LE", + /* the -ms package */ + "AB", "AE", + "BD", "DE", + "CD", "DE", + "DS", "DE", + "FS", "FE", + "ID", "DE", + "KF", "KE", + "KS", "KE", + "LD", "DE", + "LG", "NL", + "QS", "QE", + "RS", "RE", + "SM", "NL", + "XA", "XE", + "XS", "XE", + /* The -me package */ + "(b", ")b", + "(c", ")c", + "(d", ")d", + "(f", ")f", + "(l", ")l", + "(q", ")q", + "(x", ")x", + "(z", ")z", + /* Things needed by preprocessors */ + "EQ", "EN", + "TS", "TE", + /* Refer */ + "[", "]", + 0, 0 +}; + +/* + * All commands known to nroff, plus macro packages. + * Used so we can complain about unrecognized commands. + */ +char *knowncmds[MAXCMDS] = { +"$c", "$f", "$h", "$p", "$s", "(b", "(c", "(d", "(f", "(l", "(q", "(t", +"(x", "(z", ")b", ")c", ")d", ")f", ")l", ")q", ")t", ")x", ")z", "++", +"+c", "1C", "1c", "2C", "2c", "@(", "@)", "@C", "@D", "@F", "@I", "@M", +"@c", "@e", "@f", "@h", "@m", "@n", "@o", "@p", "@r", "@t", "@z", "AB", +"AE", "AF", "AI", "AL", "AM", "AS", "AT", "AU", "AX", "B", "B1", "B2", +"BD", "BE", "BG", "BL", "BS", "BT", "BX", "C1", "C2", "CD", "CM", "CT", +"D", "DA", "DE", "DF", "DL", "DS", "DT", "EC", "EF", "EG", "EH", "EM", +"EN", "EQ", "EX", "FA", "FD", "FE", "FG", "FJ", "FK", "FL", "FN", "FO", +"FQ", "FS", "FV", "FX", "H", "HC", "HD", "HM", "HO", "HU", "I", "ID", +"IE", "IH", "IM", "IP", "IX", "IZ", "KD", "KE", "KF", "KQ", "KS", "LB", +"LC", "LD", "LE", "LG", "LI", "LP", "MC", "ME", "MF", "MH", "ML", "MR", +"MT", "ND", "NE", "NH", "NL", "NP", "NS", "OF", "OH", "OK", "OP", "P", +"P1", "PF", "PH", "PP", "PT", "PX", "PY", "QE", "QP", "QS", "R", "RA", +"RC", "RE", "RL", "RP", "RQ", "RS", "RT", "S", "S0", "S2", "S3", "SA", +"SG", "SH", "SK", "SM", "SP", "SY", "T&", "TA", "TB", "TC", "TD", "TE", +"TH", "TL", "TM", "TP", "TQ", "TR", "TS", "TX", "UL", "US", "UX", "VL", +"WC", "WH", "XA", "XD", "XE", "XF", "XK", "XP", "XS", "[", "[-", "[0", +"[1", "[2", "[3", "[4", "[5", "[<", "[>", "[]", "]", "]-", "]<", "]>", +"][", "ab", "ac", "ad", "af", "am", "ar", "as", "b", "ba", "bc", "bd", +"bi", "bl", "bp", "br", "bx", "c.", "c2", "cc", "ce", "cf", "ch", "cs", +"ct", "cu", "da", "de", "di", "dl", "dn", "ds", "dt", "dw", "dy", "ec", +"ef", "eh", "el", "em", "eo", "ep", "ev", "ex", "fc", "fi", "fl", "fo", +"fp", "ft", "fz", "hc", "he", "hl", "hp", "ht", "hw", "hx", "hy", "i", +"ie", "if", "ig", "in", "ip", "it", "ix", "lc", "lg", "li", "ll", "ln", +"lo", "lp", "ls", "lt", "m1", "m2", "m3", "m4", "mc", "mk", "mo", "n1", +"n2", "na", "ne", "nf", "nh", "nl", "nm", "nn", "np", "nr", "ns", "nx", +"of", "oh", "os", "pa", "pc", "pi", "pl", "pm", "pn", "po", "pp", "ps", +"q", "r", "rb", "rd", "re", "rm", "rn", "ro", "rr", "rs", "rt", "sb", +"sc", "sh", "sk", "so", "sp", "ss", "st", "sv", "sz", "ta", "tc", "th", +"ti", "tl", "tm", "tp", "tr", "u", "uf", "uh", "ul", "vs", "wh", "xp", +"yr", 0 +}; + +int lineno; /* current line number in input file */ +char line[256]; /* the current line */ +char *cfilename; /* name of current file */ +int nfiles; /* number of files to process */ +int fflag; /* -f: ignore \f */ +int sflag; /* -s: ignore \s */ +int ncmds; /* size of knowncmds */ +int slot; /* slot in knowncmds found by binsrch */ + +char *malloc(); + +main(argc, argv) +int argc; +char **argv; +{ + FILE *f; + int i; + char *cp; + char b1[4]; + + /* Figure out how many known commands there are */ + while (knowncmds[ncmds]) + ncmds++; + while (argc > 1 && argv[1][0] == '-') { + switch(argv[1][1]) { + + /* -a: add pairs of macros */ + case 'a': + i = strlen(argv[1]) - 2; + if (i % 6 != 0) + usage(); + /* look for empty macro slots */ + for (i=0; br[i].opbr; i++) + ; + for (cp=argv[1]+3; cp[-1]; cp += 6) { + br[i].opbr = malloc(3); + strncpy(br[i].opbr, cp, 2); + br[i].clbr = malloc(3); + strncpy(br[i].clbr, cp+3, 2); + addmac(br[i].opbr); /* knows pairs are also known cmds */ + addmac(br[i].clbr); + i++; + } + break; + + /* -c: add known commands */ + case 'c': + i = strlen(argv[1]) - 2; + if (i % 3 != 0) + usage(); + for (cp=argv[1]+3; cp[-1]; cp += 3) { + if (cp[2] && cp[2] != '.') + usage(); + strncpy(b1, cp, 2); + addmac(b1); + } + break; + + /* -f: ignore font changes */ + case 'f': + fflag = 1; + break; + + /* -s: ignore size changes */ + case 's': + sflag = 1; + break; + default: + usage(); + } + argc--; argv++; + } + + nfiles = argc - 1; + + if (nfiles > 0) { + for (i=1; i=0; i--) { + complain(i); + } +} + +complain(i) +{ + pe(stk[i].lno); + printf("Unmatched "); + prop(i); + printf("\n"); +} + +prop(i) +{ + if (stk[i].pl == 0) + printf(".%s", br[stk[i].opno].opbr); + else switch(stk[i].opno) { + case SZ: + printf("\\s%c%d", stk[i].pl, stk[i].parm); + break; + case FT: + printf("\\f%c", stk[i].parm); + break; + default: + printf("Bug: stk[%d].opno = %d = .%s, .%s", + i, stk[i].opno, br[stk[i].opno].opbr, br[stk[i].opno].clbr); + } +} + +chkcmd(line, mac) +char *line; +char *mac; +{ + register int i, n; + + /* + * Check to see if it matches top of stack. + */ + if (stktop >= 0 && eq(mac, br[stk[stktop].opno].clbr)) + stktop--; /* OK. Pop & forget */ + else { + /* No. Maybe it's an opener */ + for (i=0; br[i].opbr; i++) { + if (eq(mac, br[i].opbr)) { + /* Found. Push it. */ + stktop++; + stk[stktop].opno = i; + stk[stktop].pl = 0; + stk[stktop].parm = 0; + stk[stktop].lno = lineno; + break; + } + /* + * Maybe it's an unmatched closer. + * NOTE: this depends on the fact + * that none of the closers can be + * openers too. + */ + if (eq(mac, br[i].clbr)) { + nomatch(mac); + break; + } + } + } +} + +nomatch(mac) +char *mac; +{ + register int i, j; + + /* + * Look for a match further down on stack + * If we find one, it suggests that the stuff in + * between is supposed to match itself. + */ + for (j=stktop; j>=0; j--) + if (eq(mac,br[stk[j].opno].clbr)) { + /* Found. Make a good diagnostic. */ + if (j == stktop-2) { + /* + * Check for special case \fx..\fR and don't + * complain. + */ + if (stk[j+1].opno==FT && stk[j+1].parm!='R' + && stk[j+2].opno==FT && stk[j+2].parm=='R') { + stktop = j -1; + return; + } + /* + * We have two unmatched frobs. Chances are + * they were intended to match, so we mention + * them together. + */ + pe(stk[j+1].lno); + prop(j+1); + printf(" does not match %d: ", stk[j+2].lno); + prop(j+2); + printf("\n"); + } else for (i=j+1; i <= stktop; i++) { + complain(i); + } + stktop = j-1; + return; + } + /* Didn't find one. Throw this away. */ + pe(lineno); + printf("Unmatched .%s\n", mac); +} + +/* eq: are two strings equal? */ +eq(s1, s2) +char *s1, *s2; +{ + return (strcmp(s1, s2) == 0); +} + +/* print the first part of an error message, given the line number */ +pe(lineno) +int lineno; +{ + if (nfiles > 1) + printf("%s: ", cfilename); + printf("%d: ", lineno); +} + +checkknown(mac) +char *mac; +{ + + if (eq(mac, ".")) + return; + if (binsrch(mac) >= 0) + return; + if (mac[0] == '\\' && mac[1] == '"') /* comments */ + return; + + pe(lineno); + printf("Unknown command: .%s\n", mac); +} + +/* + * We have a .de xx line in "line". Add xx to the list of known commands. + */ +addcmd(line) +char *line; +{ + char *mac; + + /* grab the macro being defined */ + mac = line+4; + while (isspace(*mac)) + mac++; + if (*mac == 0) { + pe(lineno); + printf("illegal define: %s\n", line); + return; + } + mac[2] = 0; + if (isspace(mac[1]) || mac[1] == '\\') + mac[1] = 0; + if (ncmds >= MAXCMDS) { + printf("Only %d known commands allowed\n", MAXCMDS); + exit(1); + } + addmac(mac); +} + +/* + * Add mac to the list. We should really have some kind of tree + * structure here but this is a quick-and-dirty job and I just don't + * have time to mess with it. (I wonder if this will come back to haunt + * me someday?) Anyway, I claim that .de is fairly rare in user + * nroff programs, and the register loop below is pretty fast. + */ +addmac(mac) +char *mac; +{ + register char **src, **dest, **loc; + + if (binsrch(mac) >= 0){ /* it's OK to redefine something */ +#ifdef DEBUG + printf("binsrch(%s) -> already in table\n", mac); +#endif DEBUG + return; + } + /* binsrch sets slot as a side effect */ +#ifdef DEBUG +printf("binsrch(%s) -> %d\n", mac, slot); +#endif + loc = &knowncmds[slot]; + src = &knowncmds[ncmds-1]; + dest = src+1; + while (dest > loc) + *dest-- = *src--; + *loc = malloc(3); + strcpy(*loc, mac); + ncmds++; +#ifdef DEBUG +printf("after: %s %s %s %s %s, %d cmds\n", knowncmds[slot-2], knowncmds[slot-1], knowncmds[slot], knowncmds[slot+1], knowncmds[slot+2], ncmds); +#endif +} + +/* + * Do a binary search in knowncmds for mac. + * If found, return the index. If not, return -1. + */ +binsrch(mac) +char *mac; +{ + register char *p; /* pointer to current cmd in list */ + register int d; /* difference if any */ + register int mid; /* mid point in binary search */ + register int top, bot; /* boundaries of bin search, inclusive */ + + top = ncmds-1; + bot = 0; + while (top >= bot) { + mid = (top+bot)/2; + p = knowncmds[mid]; + d = p[0] - mac[0]; + if (d == 0) + d = p[1] - mac[1]; + if (d == 0) + return mid; + if (d < 0) + bot = mid + 1; + else + top = mid - 1; + } + slot = bot; /* place it would have gone */ + return -1; +} diff --git a/usr.bin/chflags/Makefile b/usr.bin/chflags/Makefile new file mode 100644 index 0000000..a432e5f --- /dev/null +++ b/usr.bin/chflags/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= chflags +SRCS= chflags.c stat_flags.c +.PATH: ${.CURDIR}/../../bin/ls + +.include diff --git a/usr.bin/chflags/chflags.1 b/usr.bin/chflags/chflags.1 new file mode 100644 index 0000000..79c1a72 --- /dev/null +++ b/usr.bin/chflags/chflags.1 @@ -0,0 +1,123 @@ +.\" Copyright (c) 1989, 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)chflags.1 8.2 (Berkeley) 3/31/94 +.\" +.Dd March 31, 1994 +.Dt CHFLAGS 1 +.Os +.Sh NAME +.Nm chflags +.Nd change file flags +.Sh SYNOPSIS +.Nm chflags +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Ar flags +.Ar file ... +.Sh DESCRIPTION +The +.Nm chflags +utility modifies the file flags of the listed files +as specified by the +.Ar flags +operand. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl H +If the +.Fl R +option is specified, symbolic links on the command line are followed. +(Symbolic links encountered in the tree traversal are not followed.) +.It Fl L +If the +.Fl R +option is specified, all symbolic links are followed. +.It Fl P +If the +.Fl R +option is specified, no symbolic links are followed. +.It Fl R +Change the file flags for the file hierarchies rooted +in the files instead of just the files themselves. +.El +.Pp +Flags are a comma separated list of keywords. +The following keywords are currently defined: +.Bd -literal -offset indent compact +.\"arch nothing yet. +dump set the dump flag +sappnd set the system append-only flag (super-user only) +schg set the system immutable flag (super-user only) +uappnd set the user append-only flag (owner or super-user only) +uchg set the user immutable flag (owner or super-user only) +.Ed +.Pp +Putting the letters +.Dq no +before an option causes the flag to be turned off. +For example: +.Bd -literal -offset indent compact +nodump the file should never be dumped +.Ed +.Pp +Symbolic links do not have flags, so unless the +.Fl H +or +.Fl L +option is set, +.Nm chflags +on a symbolic link always succeeds and has no effect. +The +.Fl H , +.Fl L +and +.Fl P +options are ignored unless the +.Fl R +option is specified. +In addition, these options override each other and the +command's actions are determined by the last one specified. +.Pp +The +.Nm chflags +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr chflags 2 , +.Xr stat 2 , +.Xr fts 3 , +.Xr symlink 7 diff --git a/usr.bin/chflags/chflags.c b/usr.bin/chflags/chflags.c new file mode 100644 index 0000000..8abeee1 --- /dev/null +++ b/usr.bin/chflags/chflags.c @@ -0,0 +1,180 @@ +/* + * 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 copyright[] = +"@(#) Copyright (c) 1992, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)chflags.c 8.5 (Berkeley) 4/1/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +u_long string_to_flags __P((char **, u_long *, u_long *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + FTS *ftsp; + FTSENT *p; + u_long clear, set; + long val; + int Hflag, Lflag, Pflag, Rflag, ch, fts_options, oct, rval; + char *flags, *ep; + + Hflag = Lflag = Pflag = Rflag = 0; + while ((ch = getopt(argc, argv, "HLPR")) != EOF) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'R': + Rflag = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + if (argc < 2) + usage(); + + fts_options = FTS_PHYSICAL; + if (Rflag) { + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } + + flags = *argv; + if (*flags >= '0' && *flags <= '7') { + errno = 0; + val = strtol(flags, &ep, 8); + if (val < 0) + errno = ERANGE; + if (errno) + err(1, "invalid flags: %s", flags); + if (*ep) + errx(1, "invalid flags: %s", flags); + set = val; + oct = 1; + } else { + if (string_to_flags(&flags, &set, &clear)) + errx(1, "invalid flag: %s", flags); + clear = ~clear; + oct = 0; + } + + if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL) + err(1, NULL); + + for (rval = 0; (p = fts_read(ftsp)) != NULL;) { + switch (p->fts_info) { + case FTS_D: + if (Rflag) /* Change it at FTS_DP. */ + continue; + fts_set(ftsp, p, FTS_SKIP); + break; + case FTS_DNR: /* Warn, chflag, continue. */ + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + break; + case FTS_ERR: /* Warn, continue. */ + case FTS_NS: + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + continue; + case FTS_SL: /* Ignore. */ + case FTS_SLNONE: + /* + * The only symlinks that end up here are ones that + * don't point to anything and ones that we found + * doing a physical walk. + */ + continue; + default: + break; + } + if (oct) { + if (!chflags(p->fts_accpath, set)) + continue; + } else { + p->fts_statp->st_flags |= set; + p->fts_statp->st_flags &= clear; + if (!chflags(p->fts_accpath, p->fts_statp->st_flags)) + continue; + } + warn("%s", p->fts_path); + rval = 1; + } + if (errno) + err(1, "fts_read"); + exit(rval); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: chflags [-R [-H | -L | -P]] flags file ...\n"); + exit(1); +} diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile new file mode 100644 index 0000000..b68ad10 --- /dev/null +++ b/usr.bin/chpass/Makefile @@ -0,0 +1,15 @@ +# @(#)Makefile 8.2 (Berkeley) 4/2/94 + +PROG= chpass +SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c table.c util.c +BINOWN= root +BINMODE=4555 +.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw +CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw +LINKS= ${BINDIR}/chpass ${BINDIR}/chfn ${BINDIR}/chpass ${BINDIR}/chsh +MLINKS= chpass.1 chfn.1 chpass.1 chsh.1 + +afterinstall: + chflags schg /usr/bin/chpass + +.include diff --git a/usr.bin/chpass/chpass.1 b/usr.bin/chpass/chpass.1 new file mode 100644 index 0000000..1a40905 --- /dev/null +++ b/usr.bin/chpass/chpass.1 @@ -0,0 +1,231 @@ +.\" Copyright (c) 1988, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)chpass.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt CHPASS 1 +.Os +.Sh NAME +.Nm chpass +.Nd add or change user database information +.Sh SYNOPSIS +chpass +.Op Fl a Ar list +.Op Fl s Ar newshell +.Op user +.Sh DESCRIPTION +.Nm Chpass +allows editing of the user database information associated +with +.Ar user +or, by default, the current user. +The information is formatted and supplied to an editor for changes. +.Pp +Only the information that the user is allowed to change is displayed. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +The super-user is allowed to directly supply a user database +entry, in the format specified by +.Xr passwd 5 , +as an argument. +This argument must be a colon (``:'') separated list of all the +user database fields, although they may be empty. +.It Fl s +The +.Fl s +option attempts to change the user's shell to +.Ar newshell . +.El +.Pp +Possible display items are as follows: +.Pp +.Bl -tag -width "Home Directory:" -compact -offset indent +.It Login: +user's login name +.It Password: +user's encrypted password +.It Uid: +user's login +.It Gid: +user's login group +.It Change: +password change time +.It Expire: +account expiration time +.It Class: +user's general classification +.It Home Directory: +user's home directory +.It Shell: +user's login shell +.It Full Name: +user's real name +.It Location: +user's normal location +.It Home Phone: +user's home phone +.It Office Phone: +user's office phone +.El +.Pp +The +.Ar login +field is the user name used to access the computer account. +.Pp +The +.Ar password +field contains the encrypted form of the user's password. +.Pp +The +.Ar uid +field is the number associated with the +.Ar login +field. +Both of these fields should be unique across the system (and often +across a group of systems) as they control file access. +.Pp +While it is possible to have multiple entries with identical login names +and/or identical user id's, it is usually a mistake to do so. Routines +that manipulate these files will often return only one of the multiple +entries, and that one by random selection. +.Pp +The +.Ar group +field is the group that the user will be placed in at login. +Since BSD supports multiple groups (see +.Xr groups 1 ) +this field currently has little special meaning. +This field may be filled in with either a number or a group name (see +.Xr group 5 ) . +.Pp +The +.Ar change +field is the date by which the password must be changed. +.Pp +The +.Ar expire +field is the date on which the account expires. +.Pp +Both the +.Ar change +and +.Ar expire +fields should be entered in the form ``month day year'' where +.Ar month +is the month name (the first three characters are sufficient), +.Ar day +is the day of the month, and +.Ar year +is the year. +.Pp +The +.Ar class +field is currently unused. In the near future it will be a key to +a +.Xr termcap 5 +style database of user attributes. +.Pp +The user's +.Ar home directory +is the full UNIX path name where the user +will be placed at login. +.Pp +The +.Ar shell +field is the command interpreter the user prefers. +If the +.Ar shell +field is empty, the Bourne shell, +.Pa /bin/sh , +is assumed. +When altering a login shell, and not the super-user, the user +may not change from a non-standard shell or to a non-standard +shell. +Non-standard is defined as a shell not found in +.Pa /etc/shells . +.Pp +The last four fields are for storing the user's +.Ar full name , office location , +and +.Ar home +and +.Ar work telephone +numbers. +.Pp +Once the information has been verified, +.Nm chpass +uses +.Xr pwd_mkdb 8 +to update the user database. +.Sh ENVIRONMENT +The +.Xr vi 1 +editor will be used unless the environment variable EDITOR is set to +an alternate editor. +When the editor terminates, the information is re-read and used to +update the user database itself. +Only the user, or the super-user, may edit the information associated +with the user. +.Sh FILES +.Bl -tag -width /etc/master.passwd -compact +.It Pa /etc/master.passwd +The user database +.It Pa /etc/passwd +A Version 7 format password file +.It Pa /etc/chpass.XXXXXX +Temporary copy of the password file +.It Pa /etc/shells +The list of approved shells +.El +.Sh SEE ALSO +.Xr login 1 , +.Xr finger 1 , +.Xr passwd 1 , +.Xr getusershell 3 , +.Xr passwd 5 , +.Xr pwd_mkdb 8 , +.Xr vipw 8 +.Rs +.%A Robert Morris +and +.%A Ken Thompson +.%T "UNIX Password security" +.Re +.Sh BUGS +User information should (and eventually will) be stored elsewhere. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 Reno . diff --git a/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c new file mode 100644 index 0000000..0852c53 --- /dev/null +++ b/usr.bin/chpass/chpass.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "pw_copy.h" + +#include "chpass.h" +#include "pathnames.h" + +char *progname = "chpass"; +char *tempname; +uid_t uid; + +void baduser __P((void)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + enum { NEWSH, LOADENTRY, EDITENTRY } op; + struct passwd *pw, lpw; + int ch, pfd, tfd; + char *arg; + + op = EDITENTRY; + while ((ch = getopt(argc, argv, "a:s:")) != EOF) + switch(ch) { + case 'a': + op = LOADENTRY; + arg = optarg; + break; + case 's': + op = NEWSH; + arg = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + uid = getuid(); + + if (op == EDITENTRY || op == NEWSH) + switch(argc) { + case 0: + if (!(pw = getpwuid(uid))) + errx(1, "unknown user: uid %u", uid); + break; + case 1: + if (!(pw = getpwnam(*argv))) + errx(1, "unknown user: %s", *argv); + if (uid && uid != pw->pw_uid) + baduser(); + break; + default: + usage(); + } + + if (op == NEWSH) { + /* protect p_shell -- it thinks NULL is /bin/sh */ + if (!arg[0]) + usage(); + if (p_shell(arg, pw, (ENTRY *)NULL)) + pw_error((char *)NULL, 0, 1); + } + + if (op == LOADENTRY) { + if (uid) + baduser(); + pw = &lpw; + if (!pw_scan(arg, pw)) + exit(1); + } + + /* + * The temporary file/file descriptor usage is a little tricky here. + * 1: We start off with two fd's, one for the master password + * file (used to lock everything), and one for a temporary file. + * 2: Display() gets an fp for the temporary file, and copies the + * user's information into it. It then gives the temporary file + * to the user and closes the fp, closing the underlying fd. + * 3: The user edits the temporary file some number of times. + * 4: Verify() gets an fp for the temporary file, and verifies the + * contents. It can't use an fp derived from the step #2 fd, + * because the user's editor may have created a new instance of + * the file. Once the file is verified, its contents are stored + * in a password structure. The verify routine closes the fp, + * closing the underlying fd. + * 5: Delete the temporary file. + * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it + * file and copies the master password file into it, replacing + * the user record with a new one. We can't use the first + * temporary file for this because it was owned by the user. + * 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. + * The exit closes the master passwd fp/fd. + */ + pw_init(); + pfd = pw_lock(); + tfd = pw_tmp(); + + if (op == EDITENTRY) { + display(tfd, pw); + edit(pw); + (void)unlink(tempname); + tfd = pw_tmp(); + } + + pw_copy(pfd, tfd, pw); + + if (!pw_mkdb()) + pw_error((char *)NULL, 0, 1); + exit(0); +} + +void +baduser() +{ + + errx(1, "%s", strerror(EACCES)); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n"); + exit(1); +} diff --git a/usr.bin/chpass/chpass.h b/usr.bin/chpass/chpass.h new file mode 100644 index 0000000..e7891ce --- /dev/null +++ b/usr.bin/chpass/chpass.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)chpass.h 8.4 (Berkeley) 4/2/94 + */ + +struct passwd; + +typedef struct _entry { + char *prompt; + int (*func)(), restricted, len; + char *except, *save; +} ENTRY; + +/* Field numbers. */ +#define E_BPHONE 8 +#define E_HPHONE 9 +#define E_LOCATE 10 +#define E_NAME 7 +#define E_SHELL 12 + +extern ENTRY list[]; +extern uid_t uid; + +int atot __P((char *, time_t *)); +void display __P((int, struct passwd *)); +void edit __P((struct passwd *)); +char *ok_shell __P((char *)); +int p_change __P((char *, struct passwd *, ENTRY *)); +int p_class __P((char *, struct passwd *, ENTRY *)); +int p_expire __P((char *, struct passwd *, ENTRY *)); +int p_gecos __P((char *, struct passwd *, ENTRY *)); +int p_gid __P((char *, struct passwd *, ENTRY *)); +int p_hdir __P((char *, struct passwd *, ENTRY *)); +int p_login __P((char *, struct passwd *, ENTRY *)); +int p_login __P((char *, struct passwd *, ENTRY *)); +int p_passwd __P((char *, struct passwd *, ENTRY *)); +int p_shell __P((char *, struct passwd *, ENTRY *)); +int p_uid __P((char *, struct passwd *, ENTRY *)); +char *ttoa __P((time_t)); +int verify __P((struct passwd *)); diff --git a/usr.bin/chpass/edit.c b/usr.bin/chpass/edit.c new file mode 100644 index 0000000..34bd35b --- /dev/null +++ b/usr.bin/chpass/edit.c @@ -0,0 +1,213 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "chpass.h" + +extern char *tempname; + +void +edit(pw) + struct passwd *pw; +{ + struct stat begin, end; + + for (;;) { + if (stat(tempname, &begin)) + pw_error(tempname, 1, 1); + pw_edit(1); + if (stat(tempname, &end)) + pw_error(tempname, 1, 1); + if (begin.st_mtime == end.st_mtime) { + warnx("no changes made"); + pw_error(NULL, 0, 0); + } + if (verify(pw)) + break; + pw_prompt(); + } +} + +/* + * display -- + * print out the file for the user to edit; strange side-effect: + * set conditional flag if the user gets to edit the shell. + */ +void +display(fd, pw) + int fd; + struct passwd *pw; +{ + FILE *fp; + char *bp, *p, *ttoa(); + + if (!(fp = fdopen(fd, "w"))) + pw_error(tempname, 1, 1); + + (void)fprintf(fp, + "#Changing user database information for %s.\n", pw->pw_name); + if (!uid) { + (void)fprintf(fp, "Login: %s\n", pw->pw_name); + (void)fprintf(fp, "Password: %s\n", pw->pw_passwd); + (void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid); + (void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid); + (void)fprintf(fp, "Change [month day year]: %s\n", + ttoa(pw->pw_change)); + (void)fprintf(fp, "Expire [month day year]: %s\n", + ttoa(pw->pw_expire)); + (void)fprintf(fp, "Class: %s\n", pw->pw_class); + (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir); + (void)fprintf(fp, "Shell: %s\n", + *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); + } + /* Only admin can change "restricted" shells. */ + else if (ok_shell(pw->pw_shell)) + /* + * Make shell a restricted field. Ugly with a + * necklace, but there's not much else to do. + */ + (void)fprintf(fp, "Shell: %s\n", + *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); + else + list[E_SHELL].restricted = 1; + bp = pw->pw_gecos; + p = strsep(&bp, ","); + (void)fprintf(fp, "Full Name: %s\n", p ? p : ""); + p = strsep(&bp, ","); + (void)fprintf(fp, "Location: %s\n", p ? p : ""); + p = strsep(&bp, ","); + (void)fprintf(fp, "Office Phone: %s\n", p ? p : ""); + p = strsep(&bp, ","); + (void)fprintf(fp, "Home Phone: %s\n", p ? p : ""); + + (void)fchown(fd, getuid(), getgid()); + (void)fclose(fp); +} + +int +verify(pw) + struct passwd *pw; +{ + ENTRY *ep; + char *p; + struct stat sb; + FILE *fp; + int len; + char buf[LINE_MAX]; + + if (!(fp = fopen(tempname, "r"))) + pw_error(tempname, 1, 1); + if (fstat(fileno(fp), &sb)) + pw_error(tempname, 1, 1); + if (sb.st_size == 0) { + warnx("corrupted temporary file"); + goto bad; + } + while (fgets(buf, sizeof(buf), fp)) { + if (!buf[0] || buf[0] == '#') + continue; + if (!(p = strchr(buf, '\n'))) { + warnx("line too long"); + goto bad; + } + *p = '\0'; + for (ep = list;; ++ep) { + if (!ep->prompt) { + warnx("unrecognized field"); + goto bad; + } + if (!strncasecmp(buf, ep->prompt, ep->len)) { + if (ep->restricted && uid) { + warnx( + "you may not change the %s field", + ep->prompt); + goto bad; + } + if (!(p = strchr(buf, ':'))) { + warnx("line corrupted"); + goto bad; + } + while (isspace(*++p)); + if (ep->except && strpbrk(p, ep->except)) { + warnx( + "illegal character in the \"%s\" field", + ep->prompt); + goto bad; + } + if ((ep->func)(p, pw, ep)) { +bad: (void)fclose(fp); + return (0); + } + break; + } + } + } + (void)fclose(fp); + + /* Build the gecos field. */ + len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) + + strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4; + if (!(p = malloc(len))) + err(1, NULL); + (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save, + list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save); + + if (snprintf(buf, sizeof(buf), + "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s", + 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) >= sizeof(buf)) { + warnx("entries too long"); + return (0); + } + return (pw_scan(buf, pw)); +} diff --git a/usr.bin/chpass/field.c b/usr.bin/chpass/field.c new file mode 100644 index 0000000..898ba4d --- /dev/null +++ b/usr.bin/chpass/field.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)field.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chpass.h" +#include "pathnames.h" + +/* ARGSUSED */ +int +p_login(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!*p) { + warnx("empty login field"); + return (1); + } + if (*p == '-') { + warnx("login names may not begin with a hyphen"); + return (1); + } + if (!(pw->pw_name = strdup(p))) { + warnx("can't save entry"); + return (1); + } + if (strchr(p, '.')) + warnx("\'.\' is dangerous in a login name"); + for (; *p; ++p) + if (isupper(*p)) { + warnx("upper-case letters are dangerous in a login name"); + break; + } + return (0); +} + +/* ARGSUSED */ +int +p_passwd(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!*p) + pw->pw_passwd = ""; /* "NOLOGIN"; */ + else if (!(pw->pw_passwd = strdup(p))) { + warnx("can't save password entry"); + return (1); + } + + return (0); +} + +/* ARGSUSED */ +int +p_uid(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + uid_t id; + char *np; + + if (!*p) { + warnx("empty uid field"); + return (1); + } + if (!isdigit(*p)) { + warnx("illegal uid"); + return (1); + } + errno = 0; + id = strtoul(p, &np, 10); + if (*np || (id == ULONG_MAX && errno == ERANGE)) { + warnx("illegal uid"); + return (1); + } + pw->pw_uid = id; + return (0); +} + +/* ARGSUSED */ +int +p_gid(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + struct group *gr; + gid_t id; + char *np; + + if (!*p) { + warnx("empty gid field"); + return (1); + } + if (!isdigit(*p)) { + if (!(gr = getgrnam(p))) { + warnx("unknown group %s", p); + return (1); + } + pw->pw_gid = gr->gr_gid; + return (0); + } + errno = 0; + id = strtoul(p, &np, 10); + if (*np || (id == ULONG_MAX && errno == ERANGE)) { + warnx("illegal gid"); + return (1); + } + pw->pw_gid = id; + return (0); +} + +/* ARGSUSED */ +int +p_class(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!*p) + pw->pw_class = ""; + else if (!(pw->pw_class = strdup(p))) { + warnx("can't save entry"); + return (1); + } + + return (0); +} + +/* ARGSUSED */ +int +p_change(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!atot(p, &pw->pw_change)) + return (0); + warnx("illegal date for change field"); + return (1); +} + +/* ARGSUSED */ +int +p_expire(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!atot(p, &pw->pw_expire)) + return (0); + warnx("illegal date for expire field"); + return (1); +} + +/* ARGSUSED */ +int +p_gecos(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!*p) + ep->save = ""; + else if (!(ep->save = strdup(p))) { + warnx("can't save entry"); + return (1); + } + return (0); +} + +/* ARGSUSED */ +int +p_hdir(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + if (!*p) { + warnx("empty home directory field"); + return (1); + } + if (!(pw->pw_dir = strdup(p))) { + warnx("can't save entry"); + return (1); + } + return (0); +} + +/* ARGSUSED */ +int +p_shell(p, pw, ep) + char *p; + struct passwd *pw; + ENTRY *ep; +{ + char *t, *ok_shell(); + + if (!*p) { + pw->pw_shell = _PATH_BSHELL; + return (0); + } + /* only admin can change from or to "restricted" shells */ + if (uid && pw->pw_shell && !ok_shell(pw->pw_shell)) { + warnx("%s: current shell non-standard", pw->pw_shell); + return (1); + } + if (!(t = ok_shell(p))) { + if (uid) { + warnx("%s: non-standard shell", p); + return (1); + } + } + else + p = t; + if (!(pw->pw_shell = strdup(p))) { + warnx("can't save entry"); + return (1); + } + return (0); +} diff --git a/usr.bin/chpass/pathnames.h b/usr.bin/chpass/pathnames.h new file mode 100644 index 0000000..30f3c0d --- /dev/null +++ b/usr.bin/chpass/pathnames.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#undef _PATH_TMP +#define _PATH_TMP "/tmp/chpass.XXXXXX" diff --git a/usr.bin/chpass/pw_copy.c b/usr.bin/chpass/pw_copy.c new file mode 100644 index 0000000..3db04ed --- /dev/null +++ b/usr.bin/chpass/pw_copy.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * This module is used to copy the master password file, replacing a single + * record, by chpass(1) and passwd(1). + */ + +#include +#include +#include +#include + +#include +#include "pw_copy.h" + +extern char *tempname; + +void +pw_copy(ffd, tfd, pw) + int ffd, tfd; + struct passwd *pw; +{ + FILE *from, *to; + int done; + char *p, buf[8192]; + + if (!(from = fdopen(ffd, "r"))) + pw_error(_PATH_MASTERPASSWD, 1, 1); + if (!(to = fdopen(tfd, "w"))) + pw_error(tempname, 1, 1); + + for (done = 0; fgets(buf, sizeof(buf), from);) { + if (!strchr(buf, '\n')) { + warnx("%s: line too long", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } + if (done) { + (void)fprintf(to, "%s", buf); + if (ferror(to)) + goto err; + continue; + } + if (!(p = strchr(buf, ':'))) { + warnx("%s: corrupted entry", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } + *p = '\0'; + if (strcmp(buf, pw->pw_name)) { + *p = ':'; + (void)fprintf(to, "%s", buf); + if (ferror(to)) + 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); + 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); + + if (ferror(to)) +err: pw_error(NULL, 1, 1); + (void)fclose(to); +} diff --git a/usr.bin/chpass/pw_copy.h b/usr.bin/chpass/pw_copy.h new file mode 100644 index 0000000..4ef68c5 --- /dev/null +++ b/usr.bin/chpass/pw_copy.h @@ -0,0 +1,36 @@ +/* + * 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. + * + * @(#)pw_copy.h 8.1 (Berkeley) 4/2/94 + */ + +void pw_copy __P((int, int, struct passwd *)); diff --git a/usr.bin/chpass/table.c b/usr.bin/chpass/table.c new file mode 100644 index 0000000..46a12d1 --- /dev/null +++ b/usr.bin/chpass/table.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)table.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include "chpass.h" + +char e1[] = ": "; +char e2[] = ":,"; + +ENTRY list[] = { + { "login", p_login, 1, 5, e1, }, + { "password", p_passwd, 1, 8, e1, }, + { "uid", p_uid, 1, 3, e1, }, + { "gid", p_gid, 1, 3, e1, }, + { "class", p_class, 1, 5, e1, }, + { "change", p_change, 1, 6, NULL, }, + { "expire", p_expire, 1, 6, NULL, }, + { "full name", p_gecos, 0, 9, e2, }, + { "office phone", p_gecos, 0, 12, e2, }, + { "home phone", p_gecos, 0, 10, e2, }, + { "location", p_gecos, 0, 8, e2, }, + { "home directory", p_hdir, 1, 14, e1, }, + { "shell", p_shell, 0, 5, e1, }, + { NULL, 0, }, +}; diff --git a/usr.bin/chpass/util.c b/usr.bin/chpass/util.c new file mode 100644 index 0000000..ec4cc1f --- /dev/null +++ b/usr.bin/chpass/util.c @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)util.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chpass.h" +#include "pathnames.h" + +static int dmsize[] = + { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static char *months[] = + { "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", + "December", NULL }; + +char * +ttoa(tval) + time_t tval; +{ + struct tm *tp; + static char tbuf[50]; + + if (tval) { + tp = localtime(&tval); + (void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon], + tp->tm_mday, tp->tm_year + TM_YEAR_BASE); + } + else + *tbuf = '\0'; + return (tbuf); +} + +int +atot(p, store) + char *p; + time_t *store; +{ + static struct tm *lt; + char *t, **mp; + time_t tval; + int day, month, year; + + if (!*p) { + *store = 0; + return (0); + } + if (!lt) { + unsetenv("TZ"); + (void)time(&tval); + lt = localtime(&tval); + } + if (!(t = strtok(p, " \t"))) + goto bad; + for (mp = months;; ++mp) { + if (!*mp) + goto bad; + if (!strncasecmp(*mp, t, 3)) { + month = mp - months + 1; + break; + } + } + if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t)) + goto bad; + day = atoi(t); + if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t)) + goto bad; + year = atoi(t); + if (day < 1 || day > 31 || month < 1 || month > 12 || !year) + goto bad; + if (year < 100) + year += TM_YEAR_BASE; + if (year <= EPOCH_YEAR) +bad: return (1); + tval = isleap(year) && month > 2; + for (--year; year >= EPOCH_YEAR; --year) + tval += isleap(year) ? + DAYSPERLYEAR : DAYSPERNYEAR; + while (--month) + tval += dmsize[month]; + tval += day; + tval = tval * HOURSPERDAY * MINSPERHOUR * SECSPERMIN; + tval -= lt->tm_gmtoff; + *store = tval; + return (0); +} + +char * +ok_shell(name) + char *name; +{ + char *p, *sh; + + setusershell(); + while (sh = getusershell()) { + if (!strcmp(name, sh)) + return (name); + /* allow just shell name, but use "real" path */ + if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) + return (sh); + } + return (NULL); +} diff --git a/usr.bin/cksum/Makefile b/usr.bin/cksum/Makefile new file mode 100644 index 0000000..d2f09b7 --- /dev/null +++ b/usr.bin/cksum/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= cksum +SRCS= cksum.c crc.c print.c sum1.c sum2.c + +.include diff --git a/usr.bin/cksum/cksum.1 b/usr.bin/cksum/cksum.1 new file mode 100644 index 0000000..7c2cc24 --- /dev/null +++ b/usr.bin/cksum/cksum.1 @@ -0,0 +1,164 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)cksum.1 8.1 (Berkeley) 6/29/93 +.\" +.Dd June 29, 1993 +.Dt CKSUM 1 +.Os BSD 4.4 +.Sh NAME +.Nm cksum +.Nd display file checksums and block counts +.Sh SYNOPSIS +.Nm cksum +.Op Fl o Op \&1 \&| \&2 +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm cksum +utility writes to the standard output three whitespace separated +fields for each input file. +These fields are a checksum +.Tn CRC , +the total number of octets in the file and the file name. +If no file name is specified, the standard input is used and no file name +is written. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl o +Use historic algorithms instead of the (superior) default one. +.Pp +Algorithm 1 is the algorithm used by historic +.Bx +systems as the +.Xr sum 1 +algorithm and by historic +.At V +systems as the +.Xr sum +algorithm when using the +.Fl r +option. +This is a 16-bit checksum, with a right rotation before each addition; +overflow is discarded. +.Pp +Algorithm 2 is the algorithm used by historic +.At V +systems as the +default +.Xr sum +algorithm. +This is a 32-bit checksum, and is defined as follows: +.Bd -unfilled -offset indent +s = sum of all bytes; +r = s % 2^16 + (s % 2^32) / 2^16; +cksum = (r % 2^16) + r / 2^16; +.Ed +.Pp +Both algorithm 1 and 2 write to the standard output the same fields as +the default algorithm except that the size of the file in bytes is +replaced with the size of the file in blocks. +For historic reasons, the block size is 1024 for algorithm 1 and 512 +for algorithm 2. +Partial blocks are rounded up. +.El +.Pp +The default +.Tn CRC +used is based on the polynomial used for +.Tn CRC +error checking +in the networking standard +.St -iso8802-3 +The +.Tn CRC +checksum encoding is defined by the generating polynomial: +.Pp +.Bd -unfilled -offset indent +G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 +.Ed +.Pp +Mathematically, the +.Tn CRC +value corresponding to a given file is defined by +the following procedure: +.Bd -filled -offset indent +The +.Ar n +bits to be evaluated are considered to be the coefficients of a mod 2 +polynomial M(x) of degree +.Ar n Ns \-1 . +These +.Ar n +bits are the bits from the file, with the most significant bit being the most +significant bit of the first octet of the file and the last bit being the least +significant bit of the last octet, padded with zero bits (if necessary) to +achieve an integral number of octets, followed by one or more octets +representing the length of the file as a binary value, least significant octet +first. +The smallest number of octets capable of representing this integer are used. +.Pp +M(x) is multiplied by x^32 (i.e., shifted left 32 bits) and divided by +G(x) using mod 2 division, producing a remainder R(x) of degree <= 31. +.Pp +The coefficients of R(x) are considered to be a 32-bit sequence. +.Pp +The bit sequence is complemented and the result is the CRC. +.Ed +.Pp +The +.Nm cksum +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +The default calculation is identical to that given in pseudo-code +in the following +.Tn ACM +article. +.Rs +.%T "Computation of Cyclic Redundancy Checks Via Table Lookup" +.%A Dilip V. Sarwate +.%J "Communications of the \\*(tNACM\\*(sP" +.%D "August 1988" +.Re +.Sh STANDARDS +The +.Nm cksum +utility is expected to be POSIX 1003.2 compatible. +.Sh HISTORY +The +.Nm cksum +utility appears in +.Bx 4.4 . diff --git a/usr.bin/cksum/cksum.c b/usr.bin/cksum/cksum.c new file mode 100644 index 0000000..3e66ca5 --- /dev/null +++ b/usr.bin/cksum/cksum.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James W. Williams of NASA Goddard Space Flight Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)cksum.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + u_long len, val; + register int ch, fd, rval; + char *fn; + int (*cfncn) __P((int, unsigned long *, unsigned long *)); + void (*pfncn) __P((char *, unsigned long, unsigned long)); + + cfncn = crc; + pfncn = pcrc; + while ((ch = getopt(argc, argv, "o:")) != EOF) + switch(ch) { + case 'o': + if (*optarg == '1') { + cfncn = csum1; + pfncn = psum1; + } else if (*optarg == '2') { + cfncn = csum2; + pfncn = psum2; + } else { + (void)fprintf(stderr, + "cksum: illegal argument to -o option\n"); + usage(); + } + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + fd = STDIN_FILENO; + fn = NULL; + rval = 0; + do { + if (*argv) { + fn = *argv++; + if ((fd = open(fn, O_RDONLY, 0)) < 0) { + (void)fprintf(stderr, "cksum: %s: %s\n", + fn, strerror(errno)); + rval = 1; + continue; + } + } + if (cfncn(fd, &val, &len)) { + (void)fprintf(stderr, "cksum: %s: %s\n", + fn ? fn : "stdin", strerror(errno)); + rval = 1; + } else + pfncn(fn, val, len); + (void)close(fd); + } while (*argv); + exit(rval); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: cksum [-o 1 | 2] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/cksum/crc.c b/usr.bin/cksum/crc.c new file mode 100644 index 0000000..2a5eb6d --- /dev/null +++ b/usr.bin/cksum/crc.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James W. Williams of NASA Goddard Space Flight Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; +#endif /* not lint */ + +#include +#include + +static u_long crctab[] = { + 0x0, + 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, + 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, + 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, + 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, + 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, + 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, + 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, + 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, + 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, + 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, + 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, + 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, + 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, + 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, + 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, + 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, + 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, + 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, + 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, + 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, + 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, + 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, + 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, + 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, + 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, + 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, + 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, + 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, + 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, + 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, + 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, + 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, + 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, + 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +/* + * Compute a POSIX 1003.2 checksum. This routine has been broken out so that + * other programs can use it. It takes a file descriptor to read from and + * locations to store the crc and the number of bytes read. It returns 0 on + * success and 1 on failure. Errno is set on failure. + */ +u_long crc_total = ~0; /* The crc over a number of files. */ + +int +crc(fd, cval, clen) + register int fd; + u_long *cval, *clen; +{ + register u_char *p; + register int nr; + register u_long crc, len; + u_char buf[16 * 1024]; + +#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] + + crc = len = 0; + crc_total = ~crc_total; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (len += nr, p = buf; nr--; ++p) { + COMPUTE(crc, *p); + COMPUTE(crc_total, *p); + } + if (nr < 0) + return (1); + + *clen = len; + + /* Include the length of the file. */ + for (; len != 0; len >>= 8) { + COMPUTE(crc, len & 0xff); + COMPUTE(crc_total, len & 0xff); + } + + *cval = ~crc; + crc_total = ~crc_total; + return (0); +} diff --git a/usr.bin/cksum/extern.h b/usr.bin/cksum/extern.h new file mode 100644 index 0000000..ed61120 --- /dev/null +++ b/usr.bin/cksum/extern.h @@ -0,0 +1,45 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +__BEGIN_DECLS +int crc __P((int, unsigned long *, unsigned long *)); +void pcrc __P((char *, unsigned long, unsigned long)); +void psum1 __P((char *, unsigned long, unsigned long)); +void psum2 __P((char *, unsigned long, unsigned long)); +int csum1 __P((int, unsigned long *, unsigned long *)); +int csum2 __P((int, unsigned long *, unsigned long *)); +__END_DECLS diff --git a/usr.bin/cksum/print.c b/usr.bin/cksum/print.c new file mode 100644 index 0000000..d0ffeb3 --- /dev/null +++ b/usr.bin/cksum/print.c @@ -0,0 +1,73 @@ +/*- + * 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[] = "@(#)print.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include "extern.h" + +void +pcrc(fn, val, len) + char *fn; + u_long val, len; +{ + (void)printf("%lu %lu", val, len); + if (fn) + (void)printf(" %s", fn); + (void)printf("\n"); +} + +void +psum1(fn, val, len) + char *fn; + u_long val, len; +{ + (void)printf("%lu %lu", val, (len + 1023) / 1024); + if (fn) + (void)printf(" %s", fn); + (void)printf("\n"); +} + +void +psum2(fn, val, len) + char *fn; + u_long val, len; +{ + (void)printf("%lu %lu", val, (len + 511) / 512); + if (fn) + (void)printf(" %s", fn); + (void)printf("\n"); +} diff --git a/usr.bin/cksum/sum1.c b/usr.bin/cksum/sum1.c new file mode 100644 index 0000000..19eeebe --- /dev/null +++ b/usr.bin/cksum/sum1.c @@ -0,0 +1,69 @@ +/*- + * 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[] = "@(#)sum1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +int +csum1(fd, cval, clen) + register int fd; + u_long *cval, *clen; +{ + register u_long total; + register int nr; + register u_int crc; + register u_char *p; + u_char buf[8192]; + + /* + * 16-bit checksum, rotating right before each addition; + * overflow is discarded. + */ + crc = total = 0; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (total += nr, p = buf; nr--; ++p) { + if (crc & 1) + crc |= 0x10000; + crc = ((crc >> 1) + *p) & 0xffff; + } + if (nr < 0) + return(1); + + *cval = crc; + *clen = total; + return(0); +} diff --git a/usr.bin/cksum/sum2.c b/usr.bin/cksum/sum2.c new file mode 100644 index 0000000..c54d88e --- /dev/null +++ b/usr.bin/cksum/sum2.c @@ -0,0 +1,71 @@ +/*- + * 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[] = "@(#)sum2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +int +csum2(fd, cval, clen) + register int fd; + u_long *cval, *clen; +{ + register u_long crc, total; + register int nr; + register u_char *p; + u_char buf[8192]; + + /* + * Draft 8 POSIX 1003.2: + * + * s = sum of all bytes + * r = s % 2^16 + (s % 2^32) / 2^16 + * crc = (r % 2^16) + r / 2^16 + */ + crc = total = 0; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (total += nr, p = buf; nr--; ++p) + crc += *p; + if (nr < 0) + return(1); + + crc = (crc & 0xffff) + (crc >> 16); + crc = (crc & 0xffff) + (crc >> 16); + + *cval = crc; + *clen = total; + return(0); +} diff --git a/usr.bin/cmp/Makefile b/usr.bin/cmp/Makefile new file mode 100644 index 0000000..1b84ce3 --- /dev/null +++ b/usr.bin/cmp/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= cmp +SRCS= cmp.c misc.c regular.c special.c + +.include diff --git a/usr.bin/cmp/cmp.1 b/usr.bin/cmp/cmp.1 new file mode 100644 index 0000000..9db561a --- /dev/null +++ b/usr.bin/cmp/cmp.1 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1987, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)cmp.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt CMP 1 +.Os +.Sh NAME +.Nm cmp +.Nd compare two files +.Sh SYNOPSIS +.Nm cmp +.Op Fl l | Fl s +.Ar file1 file2 +.Op Ar skip1 Op Ar skip2 +.Sh DESCRIPTION +The cmp utility compares two files of any type and writes the results +to the standard output. +By default, +.Nm +is silent if the files are the same; if they differ, the byte +and line number at which the first difference occurred is reported. +.Pp +Bytes and lines are numbered beginning with one. +.Pp +The following options are available: +.Bl -tag -width flag +.It Fl l +Print the byte number (decimal) and the differing +byte values (octal) for each difference. +.It Fl s +Print nothing for differing files; return exit +status only. +.El +.Pp +The optional arguments +.Ar skip1 +and +.Ar skip2 +are the byte offsets from the beginning of +.Ar file1 +and +.Ar file2 , +respectively, where the comparison will begin. +The offset is decimal by default, but may be expressed as an hexadecimal +or octal value by preceding it with a leading ``0x'' or ``0''. +.Pp +The +.Nm cmp +utility exits with one of the following values: +.Bl -tag -width 4n +.It 0 +The files are identical. +.It 1 +The files are different; this includes the case +where one file is identical to the first part of +the other. +In the latter case, if the +.Fl s +option has not been specified, +.Nm cmp +writes to standard output that EOF was reached in the shorter +file (before any differences were found). +.It >1 +An error occurred. +.El +.Sh SEE ALSO +.Xr diff 1 , +.Xr diff3 1 +.Sh STANDARDS +The +.Nm cmp +utility is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/cmp/cmp.c b/usr.bin/cmp/cmp.c new file mode 100644 index 0000000..dc6c64e --- /dev/null +++ b/usr.bin/cmp/cmp.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1987, 1990, 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 copyright[] = +"@(#) Copyright (c) 1987, 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)cmp.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +int lflag, sflag; + +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb1, sb2; + off_t skip1, skip2; + int ch, fd1, fd2, special; + char *file1, *file2; + + while ((ch = getopt(argc, argv, "-ls")) != EOF) + switch (ch) { + case 'l': /* print all differences */ + lflag = 1; + break; + case 's': /* silent run */ + sflag = 1; + break; + case '-': /* stdin (must be after options) */ + --optind; + goto endargs; + case '?': + default: + usage(); + } +endargs: + argv += optind; + argc -= optind; + + if (lflag && sflag) + errx(ERR_EXIT, "only one of -l and -s may be specified"); + + if (argc < 2 || argc > 4) + usage(); + + /* Backward compatibility -- handle "-" meaning stdin. */ + special = 0; + if (strcmp(file1 = argv[0], "-") == 0) { + special = 1; + fd1 = 0; + file1 = "stdin"; + } + else if ((fd1 = open(file1, O_RDONLY, 0)) < 0) + err(ERR_EXIT, "%s", file1); + if (strcmp(file2 = argv[1], "-") == 0) { + if (special) + errx(ERR_EXIT, + "standard input may only be specified once"); + special = 1; + fd2 = 0; + file2 = "stdin"; + } + else if ((fd2 = open(file2, O_RDONLY, 0)) < 0) + err(ERR_EXIT, "%s", file2); + + skip1 = argc > 2 ? strtol(argv[2], NULL, 10) : 0; + skip2 = argc == 4 ? strtol(argv[3], NULL, 10) : 0; + + if (!special) { + if (fstat(fd1, &sb1)) + err(ERR_EXIT, "%s", file1); + if (!S_ISREG(sb1.st_mode)) + special = 1; + else { + if (fstat(fd2, &sb2)) + err(ERR_EXIT, "%s", file2); + if (!S_ISREG(sb2.st_mode)) + special = 1; + } + } + + if (special) + c_special(fd1, file1, skip1, fd2, file2, skip2); + else + c_regular(fd1, file1, skip1, sb1.st_size, + fd2, file2, skip2, sb2.st_size); + exit(0); +} + +static void +usage() +{ + + (void)fprintf(stderr, + "usage: cmp [-l | s] file1 file2 [skip1 [skip2]]\n"); + exit(ERR_EXIT); +} diff --git a/usr.bin/cmp/extern.h b/usr.bin/cmp/extern.h new file mode 100644 index 0000000..b01e2de --- /dev/null +++ b/usr.bin/cmp/extern.h @@ -0,0 +1,45 @@ +/*- + * 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. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + */ + +#define OK_EXIT 0 +#define DIFF_EXIT 1 +#define ERR_EXIT 2 /* error exit code */ + +void c_regular __P((int, char *, off_t, off_t, int, char *, off_t, off_t)); +void c_special __P((int, char *, off_t, int, char *, off_t)); +void diffmsg __P((char *, char *, off_t, off_t)); +void eofmsg __P((char *)); + +extern int lflag, sflag; diff --git a/usr.bin/cmp/misc.c b/usr.bin/cmp/misc.c new file mode 100644 index 0000000..d5a601d --- /dev/null +++ b/usr.bin/cmp/misc.c @@ -0,0 +1,64 @@ +/*- + * 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[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include + +#include "extern.h" + +void +eofmsg(file) + char *file; +{ + if (!sflag) + warnx("EOF on %s", file); + exit(DIFF_EXIT); +} + +void +diffmsg(file1, file2, byte, line) + char *file1, *file2; + off_t byte, line; +{ + if (!sflag) + (void)printf("%s %s differ: char %qd, line %qd\n", + file1, file2, byte, line); + exit(DIFF_EXIT); +} diff --git a/usr.bin/cmp/regular.c b/usr.bin/cmp/regular.c new file mode 100644 index 0000000..35f62d1 --- /dev/null +++ b/usr.bin/cmp/regular.c @@ -0,0 +1,98 @@ +/*- + * 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[] = "@(#)regular.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "extern.h" + +void +c_regular(fd1, file1, skip1, len1, fd2, file2, skip2, len2) + int fd1, fd2; + char *file1, *file2; + off_t skip1, len1, skip2, len2; +{ + u_char ch, *p1, *p2; + off_t byte, length, line; + int dfound; + + if (sflag && len1 != len2) + exit(1); + + if (skip1 > len1) + eofmsg(file1); + len1 -= skip1; + if (skip2 > len2) + eofmsg(file2); + len2 -= skip2; + + length = MIN(len1, len2); + if (length > SIZE_T_MAX) + return (c_special(fd1, file1, skip1, fd2, file2, skip2)); + + if ((p1 = (u_char *)mmap(NULL, + (size_t)length, PROT_READ, 0, fd1, skip1)) == (u_char *)-1) + err(ERR_EXIT, "%s", file1); + if ((p2 = (u_char *)mmap(NULL, + (size_t)length, PROT_READ, 0, fd2, skip2)) == (u_char *)-1) + err(ERR_EXIT, "%s", file2); + + dfound = 0; + for (byte = line = 1; length--; ++p1, ++p2, ++byte) { + if ((ch = *p1) != *p2) + if (lflag) { + dfound = 1; + (void)printf("%6qd %3o %3o\n", byte, ch, *p2); + } else + diffmsg(file1, file2, byte, line); + /* NOTREACHED */ + if (ch == '\n') + ++line; + } + + if (len1 != len2) + eofmsg (len1 > len2 ? file2 : file1); + if (dfound) + exit(DIFF_EXIT); +} diff --git a/usr.bin/cmp/special.c b/usr.bin/cmp/special.c new file mode 100644 index 0000000..0dcd0c5 --- /dev/null +++ b/usr.bin/cmp/special.c @@ -0,0 +1,99 @@ +/*- + * 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[] = "@(#)special.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include + +#include "extern.h" + +void +c_special(fd1, file1, skip1, fd2, file2, skip2) + int fd1, fd2; + char *file1, *file2; + off_t skip1, skip2; +{ + int ch1, ch2; + off_t byte, line; + FILE *fp1, *fp2; + int dfound; + + if ((fp1 = fdopen(fd1, "r")) == NULL) + err(ERR_EXIT, "%s", file1); + if ((fp2 = fdopen(fd2, "r")) == NULL) + err(ERR_EXIT, "%s", file2); + + while (skip1--) + if (getc(fp1) == EOF) + goto eof; + while (skip2--) + if (getc(fp2) == EOF) + goto eof; + + dfound = 0; + for (byte = line = 1;; ++byte) { + ch1 = getc(fp1); + ch2 = getc(fp2); + if (ch1 == EOF || ch2 == EOF) + break; + if (ch1 != ch2) + if (lflag) { + dfound = 1; + (void)printf("%6qd %3o %3o\n", byte, ch1, ch2); + } else + diffmsg(file1, file2, byte, line); + /* NOTREACHED */ + if (ch1 == '\n') + ++line; + } + +eof: if (ferror(fp1)) + err(ERR_EXIT, "%s", file1); + if (ferror(fp2)) + err(ERR_EXIT, "%s", file2); + if (feof(fp1)) { + if (!feof(fp2)) + eofmsg(file1); + } else + if (feof(fp2)) + eofmsg(file2); + if (dfound) + exit(DIFF_EXIT); +} diff --git a/usr.bin/col/Makefile b/usr.bin/col/Makefile new file mode 100644 index 0000000..efa0933 --- /dev/null +++ b/usr.bin/col/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= col + +.include diff --git a/usr.bin/col/README b/usr.bin/col/README new file mode 100644 index 0000000..f673f3a --- /dev/null +++ b/usr.bin/col/README @@ -0,0 +1,48 @@ +# @(#)README 8.1 (Berkeley) 6/6/93 + +col - filter out reverse line feeds. + +Options are: + -b do not print any backspaces (last character written is printed) + -f allow half line feeds in output, by default characters between + lines are pushed to the line below + -x do not compress spaces into tabs. + -l num keep (at least) num lines in memory, 128 are kept by default + +In the 32V source code to col(1) the default behavior was to NOT compress +spaces into tabs. There was a -h option which caused it to compress spaces +into tabs. There was no -x flag. + +The 32V documentation, however, was consistent with the SVID (actually, V7 +at the time) and documented a -x flag (as defined above) while making no +mention of a -h flag. Just before 4.3BSD went out, CSRG updated the manual +page to reflect the way the code worked. Suspecting that this was probably +the wrong way to go, this version adopts the SVID defaults, and no longer +documents the -h option. + +The S5 -p flag is not supported because it isn't clear what it does (looks +like a kludge introduced for a particular printer). + +Known differences between AT&T's col and this one (# is delimiter): + Input AT&T col this col + #\nabc\E7def\n# # def\nabc\r# # def\nabc\n# + #a# ## #a\n# + - last line always ends with at least one \n (or \E9) + #1234567 8\n# #1234567\t8\n# #1234567 8\n# + - single space not expanded to tab + -f #a\E8b\n# #ab\n# # b\E9\ra\n# + - can back up past first line (as far as you want) so you + *can* have a super script on the first line + #\E9_\ba\E8\nb\n# #\n_\bb\ba\n# #\n_\ba\bb\n# + - always print last character written to a position, + AT&T col claims to do this but doesn't. + +If a character is to be placed on a line that has been flushed, a warning +is produced (the AT&T col is silent). The -l flag (not in AT&T col) can +be used to increase the number of lines buffered to avoid the problem. + +General algorithm: a limited number of lines are buffered in a linked +list. When a printable character is read, it is put in the buffer of +the current line along with the column it's supposed to be in. When +a line is flushed, the characters in the line are sorted according to +column and then printed. diff --git a/usr.bin/col/col.1 b/usr.bin/col/col.1 new file mode 100644 index 0000000..2a55ef2 --- /dev/null +++ b/usr.bin/col/col.1 @@ -0,0 +1,126 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Michael Rendell. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)col.1 8.1 (Berkeley) 6/29/93 +.\" +.Dd June 29, 1993 +.Dt COL 1 +.Os +.Sh NAME +.Nm col +.Nd filter reverse line feeds from input +.Sh SYNOPSIS +.Nm col +.Op Fl bfx +.Op Fl l Ar num +.Sh DESCRIPTION +.Nm Col +filters out reverse (and half reverse) line feeds so that the output is +in the correct order with only forward and half forward line +feeds, and replaces white-space characters with tabs where possible. +This can be useful in processing the output of +.Xr nroff 1 +and +.Xr tbl 1 . +.Pp +.Nm Col +reads from the standard input and writes to the standard output. +.Pp +The options are as follows: +.Bl -tag -width "-l num " +.It Fl b +Do not output any backspaces, printing only the last character +written to each column position. +.It Fl f +Forward half line feeds are permitted (``fine'' mode). +Normally characters printed on a half line boundary are printed +on the following line. +.It Fl x +Output multiple spaces instead of tabs. +.It Fl l Ar num +Buffer at least +.Ar num +lines in memory. +By default, 128 lines are buffered. +.El +.Pp +The control sequences for carriage motion that +.Nm col +understands and their decimal values are listed in the following +table: +.Pp +.Bl -tag -width "carriage return" -compact +.It ESC\-7 +reverse line feed (escape then 7) +.It ESC\-8 +half reverse line feed (escape then 8) +.It ESC\-9 +half forward line feed (escape then 9) +.It backspace +moves back one column (8); ignored in the first column +.It carriage return +(13) +.It newline +forward line feed (10); also does carriage return +.It shift in +shift to normal character set (15) +.It shift out +shift to alternate character set (14) +.It space +moves forward one column (32) +.It tab +moves forward to next tab stop (9) +.It vertical tab +reverse line feed (11) +.El +.Pp +All unrecognized control characters and escape sequences are +discarded. +.Pp +.Nm Col +keeps track of the character set as characters are read and makes +sure the character set is correct when they are output. +.Pp +If the input attempts to back up to the last flushed line, +.Nm col +will display a warning message. +.Sh SEE ALSO +.Xr expand 1 , +.Xr nroff 1 , +.Xr tbl 1 +.Sh HISTORY +A +.Nm col +command +appeared in Version 6 AT&T UNIX. diff --git a/usr.bin/col/col.c b/usr.bin/col/col.c new file mode 100644 index 0000000..77b6dc6 --- /dev/null +++ b/usr.bin/col/col.c @@ -0,0 +1,534 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Rendell of the Memorial University of Newfoundland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)col.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#define BS '\b' /* backspace */ +#define TAB '\t' /* tab */ +#define SPACE ' ' /* space */ +#define NL '\n' /* newline */ +#define CR '\r' /* carriage return */ +#define ESC '\033' /* escape */ +#define SI '\017' /* shift in to normal character set */ +#define SO '\016' /* shift out to alternate character set */ +#define VT '\013' /* vertical tab (aka reverse line feed) */ +#define RLF '\007' /* ESC-07 reverse line feed */ +#define RHLF '\010' /* ESC-010 reverse half-line feed */ +#define FHLF '\011' /* ESC-011 forward half-line feed */ + +/* build up at least this many lines before flushing them out */ +#define BUFFER_MARGIN 32 + +typedef char CSET; + +typedef struct char_str { +#define CS_NORMAL 1 +#define CS_ALTERNATE 2 + short c_column; /* column character is in */ + CSET c_set; /* character set (currently only 2) */ + char c_char; /* character in question */ +} CHAR; + +typedef struct line_str LINE; +struct line_str { + CHAR *l_line; /* characters on the line */ + LINE *l_prev; /* previous line */ + LINE *l_next; /* next line */ + int l_lsize; /* allocated sizeof l_line */ + int l_line_len; /* strlen(l_line) */ + int l_needs_sort; /* set if chars went in out of order */ + int l_max_col; /* max column in the line */ +}; + +LINE *alloc_line __P((void)); +void dowarn __P((int)); +void flush_line __P((LINE *)); +void flush_lines __P((int)); +void flush_blanks __P((void)); +void free_line __P((LINE *)); +void usage __P((void)); +void wrerr __P((void)); +void *xmalloc __P((void *, size_t)); + +CSET last_set; /* char_set of last char printed */ +LINE *lines; +int compress_spaces; /* if doing space -> tab conversion */ +int fine; /* if `fine' resolution (half lines) */ +int max_bufd_lines; /* max # lines to keep in memory */ +int nblank_lines; /* # blanks after last flushed line */ +int no_backspaces; /* if not to output any backspaces */ + +#define PUTC(ch) \ + if (putchar(ch) == EOF) \ + wrerr(); + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + CHAR *c; + CSET cur_set; /* current character set */ + LINE *l; /* current line */ + int extra_lines; /* # of lines above first line */ + int cur_col; /* current column */ + int cur_line; /* line number of current position */ + int max_line; /* max value of cur_line */ + int this_line; /* line l points to */ + int nflushd_lines; /* number of lines that were flushed */ + int adjust, opt, warned; + + max_bufd_lines = 128; + compress_spaces = 1; /* compress spaces into tabs */ + while ((opt = getopt(argc, argv, "bfhl:x")) != EOF) + switch (opt) { + case 'b': /* do not output backspaces */ + no_backspaces = 1; + break; + case 'f': /* allow half forward line feeds */ + fine = 1; + break; + case 'h': /* compress spaces into tabs */ + compress_spaces = 1; + break; + case 'l': /* buffered line count */ + if ((max_bufd_lines = atoi(optarg)) <= 0) { + (void)fprintf(stderr, + "col: bad -l argument %s.\n", optarg); + exit(1); + } + break; + case 'x': /* do not compress spaces into tabs */ + compress_spaces = 0; + break; + case '?': + default: + usage(); + } + + if (optind != argc) + usage(); + + /* this value is in half lines */ + max_bufd_lines *= 2; + + adjust = cur_col = extra_lines = warned = 0; + cur_line = max_line = nflushd_lines = this_line = 0; + cur_set = last_set = CS_NORMAL; + lines = l = alloc_line(); + + while ((ch = getchar()) != EOF) { + if (!isgraph(ch)) { + switch (ch) { + case BS: /* can't go back further */ + if (cur_col == 0) + continue; + --cur_col; + continue; + case CR: + cur_col = 0; + continue; + case ESC: /* just ignore EOF */ + switch(getchar()) { + case RLF: + cur_line -= 2; + break; + case RHLF: + cur_line--; + break; + case FHLF: + cur_line++; + if (cur_line > max_line) + max_line = cur_line; + } + continue; + case NL: + cur_line += 2; + if (cur_line > max_line) + max_line = cur_line; + cur_col = 0; + continue; + case SPACE: + ++cur_col; + continue; + case SI: + cur_set = CS_NORMAL; + continue; + case SO: + cur_set = CS_ALTERNATE; + continue; + case TAB: /* adjust column */ + cur_col |= 7; + ++cur_col; + continue; + case VT: + cur_line -= 2; + continue; + } + continue; + } + + /* Must stuff ch in a line - are we at the right one? */ + if (cur_line != this_line - adjust) { + LINE *lnew; + int nmove; + + adjust = 0; + nmove = cur_line - this_line; + if (!fine) { + /* round up to next line */ + if (cur_line & 1) { + adjust = 1; + nmove++; + } + } + if (nmove < 0) { + for (; nmove < 0 && l->l_prev; nmove++) + l = l->l_prev; + if (nmove) { + if (nflushd_lines == 0) { + /* + * Allow backup past first + * line if nothing has been + * flushed yet. + */ + for (; nmove < 0; nmove++) { + lnew = alloc_line(); + l->l_prev = lnew; + lnew->l_next = l; + l = lines = lnew; + extra_lines++; + } + } else { + if (!warned++) + dowarn(cur_line); + cur_line -= nmove; + } + } + } else { + /* may need to allocate here */ + for (; nmove > 0 && l->l_next; nmove--) + l = l->l_next; + for (; nmove > 0; nmove--) { + lnew = alloc_line(); + lnew->l_prev = l; + l->l_next = lnew; + l = lnew; + } + } + this_line = cur_line + adjust; + nmove = this_line - nflushd_lines; + if (nmove >= max_bufd_lines + BUFFER_MARGIN) { + nflushd_lines += nmove - max_bufd_lines; + flush_lines(nmove - max_bufd_lines); + } + } + /* grow line's buffer? */ + if (l->l_line_len + 1 >= l->l_lsize) { + int need; + + need = l->l_lsize ? l->l_lsize * 2 : 90; + l->l_line = (CHAR *)xmalloc((void *) l->l_line, + (unsigned) need * sizeof(CHAR)); + l->l_lsize = need; + } + c = &l->l_line[l->l_line_len++]; + c->c_char = ch; + c->c_set = cur_set; + c->c_column = cur_col; + /* + * If things are put in out of order, they will need sorting + * when it is flushed. + */ + if (cur_col < l->l_max_col) + l->l_needs_sort = 1; + else + l->l_max_col = cur_col; + cur_col++; + } + /* goto the last line that had a character on it */ + for (; l->l_next; l = l->l_next) + this_line++; + flush_lines(this_line - nflushd_lines + extra_lines + 1); + + /* make sure we leave things in a sane state */ + if (last_set != CS_NORMAL) + PUTC('\017'); + + /* flush out the last few blank lines */ + nblank_lines = max_line - this_line; + if (max_line & 1) + nblank_lines++; + else if (!nblank_lines) + /* missing a \n on the last line? */ + nblank_lines = 2; + flush_blanks(); + exit(0); +} + +void +flush_lines(nflush) + int nflush; +{ + LINE *l; + + while (--nflush >= 0) { + l = lines; + lines = l->l_next; + if (l->l_line) { + flush_blanks(); + flush_line(l); + } + nblank_lines++; + if (l->l_line) + (void)free((void *)l->l_line); + free_line(l); + } + if (lines) + lines->l_prev = NULL; +} + +/* + * Print a number of newline/half newlines. If fine flag is set, nblank_lines + * is the number of half line feeds, otherwise it is the number of whole line + * feeds. + */ +void +flush_blanks() +{ + int half, i, nb; + + half = 0; + nb = nblank_lines; + if (nb & 1) { + if (fine) + half = 1; + else + nb++; + } + nb /= 2; + for (i = nb; --i >= 0;) + PUTC('\n'); + if (half) { + PUTC('\033'); + PUTC('9'); + if (!nb) + PUTC('\r'); + } + nblank_lines = 0; +} + +/* + * Write a line to stdout taking care of space to tab conversion (-h flag) + * and character set shifts. + */ +void +flush_line(l) + LINE *l; +{ + CHAR *c, *endc; + int nchars, last_col, this_col; + + last_col = 0; + nchars = l->l_line_len; + + if (l->l_needs_sort) { + static CHAR *sorted; + static int count_size, *count, i, save, sorted_size, tot; + + /* + * Do an O(n) sort on l->l_line by column being careful to + * preserve the order of characters in the same column. + */ + if (l->l_lsize > sorted_size) { + sorted_size = l->l_lsize; + sorted = (CHAR *)xmalloc((void *)sorted, + (unsigned)sizeof(CHAR) * sorted_size); + } + if (l->l_max_col >= count_size) { + count_size = l->l_max_col + 1; + count = (int *)xmalloc((void *)count, + (unsigned)sizeof(int) * count_size); + } + memset((char *)count, 0, sizeof(int) * l->l_max_col + 1); + for (i = nchars, c = l->l_line; --i >= 0; c++) + count[c->c_column]++; + + /* + * calculate running total (shifted down by 1) to use as + * indices into new line. + */ + for (tot = 0, i = 0; i <= l->l_max_col; i++) { + save = count[i]; + count[i] = tot; + tot += save; + } + + for (i = nchars, c = l->l_line; --i >= 0; c++) + sorted[count[c->c_column]++] = *c; + c = sorted; + } else + c = l->l_line; + while (nchars > 0) { + this_col = c->c_column; + endc = c; + do { + ++endc; + } while (--nchars > 0 && this_col == endc->c_column); + + /* if -b only print last character */ + if (no_backspaces) + c = endc - 1; + + if (this_col > last_col) { + int nspace = this_col - last_col; + + if (compress_spaces && nspace > 1) { + int ntabs; + + ntabs = this_col / 8 - last_col / 8; + nspace -= ntabs * 8; + while (--ntabs >= 0) + PUTC('\t'); + } + while (--nspace >= 0) + PUTC(' '); + last_col = this_col; + } + last_col++; + + for (;;) { + if (c->c_set != last_set) { + switch (c->c_set) { + case CS_NORMAL: + PUTC('\017'); + break; + case CS_ALTERNATE: + PUTC('\016'); + } + last_set = c->c_set; + } + PUTC(c->c_char); + if (++c >= endc) + break; + PUTC('\b'); + } + } +} + +#define NALLOC 64 + +static LINE *line_freelist; + +LINE * +alloc_line() +{ + LINE *l; + int i; + + if (!line_freelist) { + l = (LINE *)xmalloc((void *)NULL, sizeof(LINE) * NALLOC); + line_freelist = l; + for (i = 1; i < NALLOC; i++, l++) + l->l_next = l + 1; + l->l_next = NULL; + } + l = line_freelist; + line_freelist = l->l_next; + + memset(l, 0, sizeof(LINE)); + return (l); +} + +void +free_line(l) + LINE *l; +{ + + l->l_next = line_freelist; + line_freelist = l; +} + +void * +xmalloc(p, size) + void *p; + size_t size; +{ + + if (!(p = (void *)realloc(p, size))) + err(1, NULL); + return (p); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: col [-bfx] [-l nline]\n"); + exit(1); +} + +void +wrerr() +{ + + (void)fprintf(stderr, "col: write error.\n"); + exit(1); +} + +void +dowarn(line) + int line; +{ + + warnx("warning: can't back up %s", + line < 0 ? "past first line" : "-- line already flushed"); +} diff --git a/usr.bin/colcrt/Makefile b/usr.bin/colcrt/Makefile new file mode 100644 index 0000000..e03ab0c --- /dev/null +++ b/usr.bin/colcrt/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= colcrt + +.include diff --git a/usr.bin/colcrt/colcrt.1 b/usr.bin/colcrt/colcrt.1 new file mode 100644 index 0000000..a9447af --- /dev/null +++ b/usr.bin/colcrt/colcrt.1 @@ -0,0 +1,108 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)colcrt.1 8.1 (Berkeley) 6/30/93 +.\" +.Dd June 30, 1993 +.Dt COLCRT 1 +.Os BSD 3 +.Sh NAME +.Nm colcrt +.Nd filter nroff output for CRT previewing +.Sh SYNOPSIS +.Nm colcrt +.Op Fl +.Op Fl \&2 +.Op Ar +.Sh DESCRIPTION +.Nm Colcrt +provides virtual half-line and reverse line feed sequences +for terminals without such capability, and on which overstriking +is destructive. +Half-line characters and underlining (changed to dashing `\-') +are placed on new lines in between the normal output lines. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl +Suppress all underlining. +This option is especially useful for previewing +.Em allboxed +tables from +.Xr tbl 1 . +.It Fl 2 +Causes all half-lines to be printed, effectively double spacing the output. +Normally, a minimal space output format is used which will suppress empty +lines. +The program never suppresses two consecutive empty lines, however. +The +.Fl 2 +option is useful for sending output to the line printer when the output +contains superscripts and subscripts which would otherwise be invisible. +.El +.Sh EXAMPLES +A typical use of +.Nm colcrt +would be +.Bd -literal +tbl exum2.n \&| nroff \-ms \&| colcrt \- \&| more +.Ed +.Sh SEE ALSO +.Xr nroff 1 , +.Xr troff 1 , +.Xr col 1 , +.Xr more 1 , +.Xr ul 1 +.Sh BUGS +Should fold underlines onto blanks even with the +.Ql Fl +option so that +a true underline character would show. +.Pp +Can't back up more than 102 lines. +.Pp +General overstriking is lost; +as a special case +.Ql \&| +overstruck with +.Ql \- +or underline becomes +.Ql \&+ . +.Pp +Lines are trimmed to 132 characters. +.Pp +Some provision should be made for processing superscripts and subscripts +in documents which are already double-spaced. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/colcrt/colcrt.c b/usr.bin/colcrt/colcrt.c new file mode 100644 index 0000000..9e6136b --- /dev/null +++ b/usr.bin/colcrt/colcrt.c @@ -0,0 +1,251 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)colcrt.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +/* + * colcrt - replaces col for crts with new nroff esp. when using tbl. + * Bill Joy UCB July 14, 1977 + * + * This filter uses a screen buffer, 267 half-lines by 132 columns. + * It interprets the up and down sequences generated by the new + * nroff when used with tbl and by \u \d and \r. + * General overstriking doesn't work correctly. + * Underlining is split onto multiple lines, etc. + * + * Option - suppresses all underlining. + * Option -2 forces printing of all half lines. + */ + +char page[267][132]; + +int outline = 1; +int outcol; + +char suppresul; +char printall; + +char *progname; +FILE *f; + +main(argc, argv) + int argc; + char *argv[]; +{ + register c; + register char *cp, *dp; + + argc--; + progname = *argv++; + while (argc > 0 && argv[0][0] == '-') { + switch (argv[0][1]) { + case 0: + suppresul = 1; + break; + case '2': + printall = 1; + break; + default: + printf("usage: %s [ - ] [ -2 ] [ file ... ]\n", progname); + fflush(stdout); + exit(1); + } + argc--; + argv++; + } + do { + if (argc > 0) { + close(0); + if (!(f = fopen(argv[0], "r"))) { + fflush(stdout); + perror(argv[0]); + exit (1); + } + argc--; + argv++; + } + for (;;) { + c = getc(stdin); + if (c == -1) { + pflush(outline); + fflush(stdout); + break; + } + switch (c) { + case '\n': + if (outline >= 265) + pflush(62); + outline += 2; + outcol = 0; + continue; + case '\016': + case '\017': + continue; + case 033: + c = getc(stdin); + switch (c) { + case '9': + if (outline >= 266) + pflush(62); + outline++; + continue; + case '8': + if (outline >= 1) + outline--; + continue; + case '7': + outline -= 2; + if (outline < 0) + outline = 0; + continue; + default: + continue; + } + case '\b': + if (outcol) + outcol--; + continue; + case '\t': + outcol += 8; + outcol &= ~7; + outcol--; + c = ' '; + default: + if (outcol >= 132) { + outcol++; + continue; + } + cp = &page[outline][outcol]; + outcol++; + if (c == '_') { + if (suppresul) + continue; + cp += 132; + c = '-'; + } + if (*cp == 0) { + *cp = c; + dp = cp - outcol; + for (cp--; cp >= dp && *cp == 0; cp--) + *cp = ' '; + } else + if (plus(c, *cp) || plus(*cp, c)) + *cp = '+'; + else if (*cp == ' ' || *cp == 0) + *cp = c; + continue; + } + } + } while (argc > 0); + fflush(stdout); + exit(0); +} + +plus(c, d) + char c, d; +{ + + return (c == '|' && d == '-' || d == '_'); +} + +int first; + +pflush(ol) + int ol; +{ + register int i, j; + register char *cp; + char lastomit; + int l; + + l = ol; + lastomit = 0; + if (l > 266) + l = 266; + else + l |= 1; + for (i = first | 1; i < l; i++) { + move(i, i - 1); + move(i, i + 1); + } + for (i = first; i < l; i++) { + cp = page[i]; + if (printall == 0 && lastomit == 0 && *cp == 0) { + lastomit = 1; + continue; + } + lastomit = 0; + printf("%s\n", cp); + } + bcopy(page[ol], page, (267 - ol) * 132); + bzero(page[267- ol], ol * 132); + outline -= ol; + outcol = 0; + first = 1; +} + +move(l, m) + int l, m; +{ + register char *cp, *dp; + + for (cp = page[l], dp = page[m]; *cp; cp++, dp++) { + switch (*cp) { + case '|': + if (*dp != ' ' && *dp != '|' && *dp != 0) + return; + break; + case ' ': + break; + default: + return; + } + } + if (*cp == 0) { + for (cp = page[l], dp = page[m]; *cp; cp++, dp++) + if (*cp == '|') + *dp = '|'; + else if (*dp == 0) + *dp = ' '; + page[l][0] = 0; + } +} diff --git a/usr.bin/colrm/Makefile b/usr.bin/colrm/Makefile new file mode 100644 index 0000000..b9c8341 --- /dev/null +++ b/usr.bin/colrm/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= colrm + +.include diff --git a/usr.bin/colrm/colrm.1 b/usr.bin/colrm/colrm.1 new file mode 100644 index 0000000..5700b54 --- /dev/null +++ b/usr.bin/colrm/colrm.1 @@ -0,0 +1,78 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)colrm.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt COLRM 1 +.Os BSD 3 +.Sh NAME +.Nm colrm +.Nd remove columns from a file +.Sh SYNOPSIS +.Nm colrm +.Op Ar start Op Ar stop +.Sh DESCRIPTION +.Nm Colrm +removes selected columns from the lines of a file. +A column is defined as a single character in a line. +Input is read from the standard input. +Output is written to the standard output. +.Pp +If only the +.Ar start +column is specified, columns numbered less than the +.Ar start +column will be written. +If both +.Ar start +and +.Ar stop +columns are specified, columns numbered less than the +.Ar start +column +or greater than the +.Ar stop +column will be written. +Column numbering starts with one, not zero. +.Pp +Tab characters increment the column count to the next multiple of eight. +Backspace characters decrement the column count by one. +.Sh SEE ALSO +.Xr awk 1 , +.Xr column 1 , +.Xr cut 1 , +.Xr paste 1 +.Sh HISTORY +The +.Nm colrm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/colrm/colrm.c b/usr.bin/colrm/colrm.c new file mode 100644 index 0000000..a7c7a65 --- /dev/null +++ b/usr.bin/colrm/colrm.c @@ -0,0 +1,167 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)colrm.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#define TAB 8 + +void err __P((const char *, ...)); +void check __P((FILE *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register u_long column, start, stop; + register int ch; + char *p; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + start = stop = 0; + switch(argc) { + case 2: + stop = strtol(argv[1], &p, 10); + if (stop <= 0 || *p) + err("illegal column -- %s", argv[1]); + /* FALLTHROUGH */ + case 1: + start = strtol(argv[0], &p, 10); + if (start <= 0 || *p) + err("illegal column -- %s", argv[0]); + break; + case 0: + break; + default: + usage(); + } + + if (stop && start > stop) + err("illegal start and stop columns"); + + for (column = 0;;) { + switch (ch = getchar()) { + case EOF: + check(stdin); + break; + case '\b': + if (column) + --column; + break; + case '\n': + column = 0; + break; + case '\t': + column = (column + TAB) & ~(TAB - 1); + break; + default: + ++column; + break; + } + + if ((!start || column < start || stop && column > stop) && + putchar(ch) == EOF) + check(stdout); + } +} + +void +check(stream) + FILE *stream; +{ + if (feof(stream)) + exit(0); + if (ferror(stream)) + err("%s: %s", + stream == stdin ? "stdin" : "stdout", strerror(errno)); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: colrm [start [stop]]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "colrm: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/column/Makefile b/usr.bin/column/Makefile new file mode 100644 index 0000000..1c304e2 --- /dev/null +++ b/usr.bin/column/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= column + +.include diff --git a/usr.bin/column/column.1 b/usr.bin/column/column.1 new file mode 100644 index 0000000..05d6a0f --- /dev/null +++ b/usr.bin/column/column.1 @@ -0,0 +1,99 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)column.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Os +.Dt COLUMN 1 +.Sh NAME +.Nm column +.Nd columnate lists +.Sh SYNOPSIS +.Nm column +.Op Fl tx +.Op Fl c Ar columns +.Op Fl s Ar sep +.Op Ar +.Sh DESCRIPTION +The +.Nm column +utility formats its input into multiple columns. +Rows are filled before columns. +Input is taken from +.Ar file +operands, or, by default, from the standard input. +Empty lines are ignored. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl c +Output is formatted for a display +.Ar columns +wide. +.It Fl s +Specify a set of characters to be used to delimit columns for the +.Fl t +option. +.It Fl t +Determine the number of columns the input contains and create a table. +Columns are delimited with whitespace, by default, or with the characters +supplied using the +.Fl s +option. +Useful for pretty-printing displays. +.It Fl x +Fill columns before filling rows. +.El +.Pp +.Nm Column +exits 0 on success, >0 if an error occurred. +.Sh ENVIRONMENT +.Bl -tag -width COLUMNS +.It Ev COLUMNS +The environment variable +.Ev COLUMNS +is used to determine the size of +the screen if no other information is available. +.El +.Sh EXAMPLES +.Dl (printf \&"PERM LINKS OWNER SIZE MONTH DAY HH:MM/YEAR NAME\en\&"\ \&;\ \&\e +.Dl ls -l \&| sed 1d) \&| column -t +.Sh SEE ALSO +.Xr colrm 1 , +.Xr ls 1 , +.Xr paste 1 , +.Xr sort 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 Reno . diff --git a/usr.bin/column/column.c b/usr.bin/column/column.c new file mode 100644 index 0000000..d3f71c5 --- /dev/null +++ b/usr.bin/column/column.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)column.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +void c_columnate __P((void)); +void *emalloc __P((int)); +void input __P((FILE *)); +void maketbl __P((void)); +void print __P((void)); +void r_columnate __P((void)); +void usage __P((void)); + +int termwidth = 80; /* default terminal width */ + +int entries; /* number of records */ +int eval; /* exit value */ +int maxlength; /* longest record */ +char **list; /* array of pointers to records */ +char *separator = "\t "; /* field separator for table option */ + +int +main(argc, argv) + int argc; + char **argv; +{ + struct winsize win; + FILE *fp; + int ch, tflag, xflag; + char *p; + + if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { + if (p = getenv("COLUMNS")) + termwidth = atoi(p); + } else + termwidth = win.ws_col; + + tflag = xflag = 0; + while ((ch = getopt(argc, argv, "c:s:tx")) != EOF) + switch(ch) { + case 'c': + termwidth = atoi(optarg); + break; + case 's': + separator = optarg; + break; + case 't': + tflag = 1; + break; + case 'x': + xflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!*argv) + input(stdin); + else for (; *argv; ++argv) + if (fp = fopen(*argv, "r")) { + input(fp); + (void)fclose(fp); + } else { + warn("%s", *argv); + eval = 1; + } + + if (!entries) + exit(eval); + + if (tflag) + maketbl(); + else if (maxlength >= termwidth) + print(); + else if (xflag) + c_columnate(); + else + r_columnate(); + exit(eval); +} + +#define TAB 8 +void +c_columnate() +{ + int chcnt, col, cnt, endcol, numcols; + char **lp; + + maxlength = (maxlength + TAB) & ~(TAB - 1); + numcols = termwidth / maxlength; + endcol = maxlength; + for (chcnt = col = 0, lp = list;; ++lp) { + chcnt += printf("%s", *lp); + if (!--entries) + break; + if (++col == numcols) { + chcnt = col = 0; + endcol = maxlength; + putchar('\n'); + } else { + while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { + (void)putchar('\t'); + chcnt = cnt; + } + endcol += maxlength; + } + } + if (chcnt) + putchar('\n'); +} + +void +r_columnate() +{ + int base, chcnt, cnt, col, endcol, numcols, numrows, row; + + maxlength = (maxlength + TAB) & ~(TAB - 1); + numcols = termwidth / maxlength; + numrows = entries / numcols; + if (entries % numcols) + ++numrows; + + for (row = 0; row < numrows; ++row) { + endcol = maxlength; + for (base = row, chcnt = col = 0; col < numcols; ++col) { + chcnt += printf("%s", list[base]); + if ((base += numrows) >= entries) + break; + while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { + (void)putchar('\t'); + chcnt = cnt; + } + endcol += maxlength; + } + putchar('\n'); + } +} + +void +print() +{ + int cnt; + char **lp; + + for (cnt = entries, lp = list; cnt--; ++lp) + (void)printf("%s\n", *lp); +} + +typedef struct _tbl { + char **list; + int cols, *len; +} TBL; +#define DEFCOLS 25 + +void +maketbl() +{ + TBL *t; + int coloff, cnt; + char *p, **lp; + int *lens, maxcols; + TBL *tbl; + char **cols; + + t = tbl = emalloc(entries * sizeof(TBL)); + cols = emalloc((maxcols = DEFCOLS) * sizeof(char *)); + lens = emalloc(maxcols * sizeof(int)); + for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { + for (coloff = 0, p = *lp; cols[coloff] = strtok(p, separator); + p = NULL) + if (++coloff == maxcols) { + if (!(cols = realloc(cols, (u_int)maxcols + + DEFCOLS * sizeof(char *))) || + !(lens = realloc(lens, + (u_int)maxcols + DEFCOLS * sizeof(int)))) + err(1, NULL); + memset((char *)lens + maxcols * sizeof(int), + 0, DEFCOLS * sizeof(int)); + maxcols += DEFCOLS; + } + t->list = emalloc(coloff * sizeof(char *)); + t->len = emalloc(coloff * sizeof(int)); + for (t->cols = coloff; --coloff >= 0;) { + t->list[coloff] = cols[coloff]; + t->len[coloff] = strlen(cols[coloff]); + if (t->len[coloff] > lens[coloff]) + lens[coloff] = t->len[coloff]; + } + } + for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) { + for (coloff = 0; coloff < t->cols - 1; ++coloff) + (void)printf("%s%*s", t->list[coloff], + lens[coloff] - t->len[coloff] + 2, " "); + (void)printf("%s\n", t->list[coloff]); + } +} + +#define DEFNUM 1000 +#define MAXLINELEN (LINE_MAX + 1) + +void +input(fp) + FILE *fp; +{ + static int maxentry; + int len; + char *p, buf[MAXLINELEN]; + + if (!list) + list = emalloc((maxentry = DEFNUM) * sizeof(char *)); + while (fgets(buf, MAXLINELEN, fp)) { + for (p = buf; *p && isspace(*p); ++p); + if (!*p) + continue; + if (!(p = strchr(p, '\n'))) { + warnx("line too long"); + eval = 1; + continue; + } + *p = '\0'; + len = p - buf; + if (maxlength < len) + maxlength = len; + if (entries == maxentry) { + maxentry += DEFNUM; + if (!(list = realloc(list, + (u_int)maxentry * sizeof(char *)))) + err(1, NULL); + } + list[entries++] = strdup(buf); + } +} + +void * +emalloc(size) + int size; +{ + char *p; + + if (!(p = malloc(size))) + err(1, NULL); + memset(p, 0, size); + return (p); +} + +void +usage() +{ + + (void)fprintf(stderr, + "usage: column [-tx] [-c columns] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/comm/Makefile b/usr.bin/comm/Makefile new file mode 100644 index 0000000..6942023 --- /dev/null +++ b/usr.bin/comm/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= comm + +.include diff --git a/usr.bin/comm/comm.1 b/usr.bin/comm/comm.1 new file mode 100644 index 0000000..0897430 --- /dev/null +++ b/usr.bin/comm/comm.1 @@ -0,0 +1,94 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)comm.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Os +.Dt COMM 1 +.Sh NAME +.Nm comm +.Nd select or reject lines common to two files +.Sh SYNOPSIS +.Nm comm +.Op Fl 123 +.Ar file1 file2 +.Sh DESCRIPTION +The +.Nm comm +utility reads +.Ar file1 +and +.Ar file2 , +which should be +sorted lexically, and produces three text +columns as output: lines only in +.Ar file1 ; +lines only in +.Ar file2 ; +and lines in both files. +.Pp +The filename ``-'' means the standard input. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl 1 +Suppress printing of column 1. +.It Fl 2 +Suppress printing of column 2. +.It Fl 3 +Suppress printing of column 3. +.El +.Pp +Each column will have a number of tab characters prepended to it +equal to the number of lower numbered columns that are being printed. +For example, if column number two is being suppressed, lines printed +in column number one will not have any tabs preceding them, and lines +printed in column number three will have one. +.Pp +.Nm Comm +assumes that the files are lexically sorted; all characters +participate in line comparisons. +.Pp +.Nm Comm +exits 0 on success, >0 if an error occurred. +.Sh SEE ALSO +.Xr cmp 1 , +.Xr diff 1 , +.Xr sort 1 , +.Xr uniq 1 +.Sh STANDARDS +The +.Nm comm +command is expected to be POSIX 1003.2 compatible. diff --git a/usr.bin/comm/comm.c b/usr.bin/comm/comm.c new file mode 100644 index 0000000..8ffbbb5 --- /dev/null +++ b/usr.bin/comm/comm.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Case Larsen. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)comm.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#define MAXLINELEN (LINE_MAX + 1) + +char *tabs[] = { "", "\t", "\t\t" }; + +FILE *file __P((char *)); +void show __P((FILE *, char *, char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int comp, file1done, file2done, read1, read2; + int ch, flag1, flag2, flag3; + FILE *fp1, *fp2; + char *col1, *col2, *col3; + char **p, line1[MAXLINELEN], line2[MAXLINELEN]; + + flag1 = flag2 = flag3 = 1; + while ((ch = getopt(argc, argv, "-123")) != EOF) + switch(ch) { + case '-': + --optind; + goto done; + case '1': + flag1 = 0; + break; + case '2': + flag2 = 0; + break; + case '3': + flag3 = 0; + break; + case '?': + default: + usage(); + } +done: argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + fp1 = file(argv[0]); + fp2 = file(argv[1]); + + /* for each column printed, add another tab offset */ + p = tabs; + col1 = col2 = col3 = NULL; + if (flag1) + col1 = *p++; + if (flag2) + col2 = *p++; + if (flag3) + col3 = *p; + + for (read1 = read2 = 1;;) { + /* read next line, check for EOF */ + if (read1) + file1done = !fgets(line1, MAXLINELEN, fp1); + if (read2) + file2done = !fgets(line2, MAXLINELEN, fp2); + + /* if one file done, display the rest of the other file */ + if (file1done) { + if (!file2done && col2) + show(fp2, col2, line2); + break; + } + if (file2done) { + if (!file1done && col1) + show(fp1, col1, line1); + break; + } + + /* lines are the same */ + if (!(comp = strcmp(line1, line2))) { + read1 = read2 = 1; + if (col3) + (void)printf("%s%s", col3, line1); + continue; + } + + /* lines are different */ + if (comp < 0) { + read1 = 1; + read2 = 0; + if (col1) + (void)printf("%s%s", col1, line1); + } else { + read1 = 0; + read2 = 1; + if (col2) + (void)printf("%s%s", col2, line2); + } + } + exit(0); +} + +void +show(fp, offset, buf) + FILE *fp; + char *offset, *buf; +{ + + do { + (void)printf("%s%s", offset, buf); + } while (fgets(buf, MAXLINELEN, fp)); +} + +FILE * +file(name) + char *name; +{ + FILE *fp; + + if (!strcmp(name, "-")) + return (stdin); + if ((fp = fopen(name, "r")) == NULL) { + (void)fprintf(stderr, "comm: %s: %s\n", name, strerror(errno)); + exit(1); + } + return (fp); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: comm [-123] file1 file2\n"); + exit(1); +} diff --git a/usr.bin/compress/Makefile b/usr.bin/compress/Makefile new file mode 100644 index 0000000..6a06830 --- /dev/null +++ b/usr.bin/compress/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.2 (Berkeley) 4/17/94 + +PROG= compress +SRCS= compress.c zopen.c +LINKS= ${BINDIR}/compress ${BINDIR}/uncompress +MLINKS= compress.1 uncompress.1 compress.1 zcat.1 + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/zcat.sh ${DESTDIR}/usr/bin/zcat + +.include diff --git a/usr.bin/compress/compress.1 b/usr.bin/compress/compress.1 new file mode 100644 index 0000000..74b7348 --- /dev/null +++ b/usr.bin/compress/compress.1 @@ -0,0 +1,172 @@ +.\" Copyright (c) 1986, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" James A. Woods, derived from original work by Spencer Thomas +.\" and Joseph Orost. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)compress.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt COMPRESS 1 +.Os BSD 4.3 +.Sh NAME +.Nm compress , +.Nm uncompress , +.Nm zcat +.Nd compress and expand data +.Sh SYNOPSIS +.Nm compress +.Op Fl cfv +.Op Fl b Ar bits +.Op Ar +.Nm uncompress +.Op Fl cfv +.Op Ar +.Nm zcat +.Op Ar +.Sh DESCRIPTION +.Nm Compress +reduces the size of the named files using adaptive Lempel-Ziv coding. +Each +.Ar file +is renamed to the same name plus the extension +.Dq .Z . +As many of the modification time, access time, file flags, file mode, +user ID, and group ID as allowed by permissions are retained in the +new file. +If compression would not reduce the size of a +.Ar file , +the file is ignored. +.Pp +.Nm Uncompress +restores the compressed files to their original form, renaming the +files by deleting the +.Dq .Z +extension. +.Pp +.Nm Zcat +is an alias for +.Dq "uncompress -c" . +.Pp +If renaming the files would cause files to be overwritten and the standard +input device is a terminal, the user is prompted (on the standard error +output) for confirmation. +If prompting is not possible or confirmation is not received, the files +are not overwritten. +.Pp +If no files are specified, the standard input is compressed or uncompressed +to the standard output. +If either the input and output files are not regular files, the checks for +reduction in size and file overwriting are not performed, the input file is +not removed, and the attributes of the input file are not retained. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b +Specify the +.Ar bits +code limit (see below). +.It Fl c +Compressed or uncompressed output is written to the standard output. +No files are modified. +.It Fl f +Force compression of +.Ar file , +even if it is not actually reduced in size. +Additionally, files are overwritten without prompting for confirmation. +.It Fl v +Print the percentage reduction of each file. +.El +.Pp +.Nm Compress +uses a modified Lempel-Ziv algorithm. +Common substrings in the file are first replaced by 9-bit codes 257 and up. +When code 512 is reached, the algorithm switches to 10-bit codes and +continues to use more bits until the +limit specified by the +.Fl b +flag is reached (the default is 16). +.Ar Bits +must be between 9 and 16. +.Pp +After the +.Ar bits +limit is reached, +.Nm compress +periodically checks the compression ratio. +If it is increasing, +.Nm compress +continues to use the existing code dictionary. +However, if the compression ratio decreases, +.Nm compress +discards the table of substrings and rebuilds it from scratch. This allows +the algorithm to adapt to the next "block" of the file. +.Pp +The +.Fl b +flag is omitted for +.Ar uncompress +since the +.Ar bits +parameter specified during compression +is encoded within the output, along with +a magic number to ensure that neither decompression of random data nor +recompression of compressed data is attempted. +.Pp +.ne 8 +The amount of compression obtained depends on the size of the +input, the number of +.Ar bits +per code, and the distribution of common substrings. +Typically, text such as source code or English is reduced by 50\-60%. +Compression is generally much better than that achieved by Huffman +coding (as used in the historical command pack), or adaptive Huffman +coding (as used in the historical command compact), and takes less +time to compute. +.Pp +The +.Nm compress +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Rs +.%A Welch, Terry A. +.%D June, 1984 +.%T "A Technique for High Performance Data Compression" +.%J "IEEE Computer" +.%V 17:6 +.%P pp. 8-19 +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/compress/compress.c b/usr.bin/compress/compress.c new file mode 100644 index 0000000..d66d224 --- /dev/null +++ b/usr.bin/compress/compress.c @@ -0,0 +1,444 @@ +/*- + * 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 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[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +void compress __P((char *, char *, int)); +void cwarn __P((const char *, ...)); +void cwarnx __P((const char *, ...)); +void decompress __P((char *, char *, int)); +int permission __P((char *)); +void setfile __P((char *, struct stat *)); +void usage __P((int)); + +int eval, force, verbose; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + enum {COMPRESS, DECOMPRESS} style; + size_t len; + int bits, cat, ch; + char *p, newname[MAXPATHLEN]; + + if ((p = rindex(argv[0], '/')) == NULL) + p = argv[0]; + else + ++p; + if (!strcmp(p, "uncompress")) + style = DECOMPRESS; + else if (!strcmp(p, "compress")) + style = COMPRESS; + else + errx(1, "unknown program name"); + + bits = cat = 0; + while ((ch = getopt(argc, argv, "b:cdfv")) != EOF) + switch(ch) { + case 'b': + bits = strtol(optarg, &p, 10); + if (*p) + errx(1, "illegal bit count -- %s", optarg); + break; + case 'c': + cat = 1; + break; + case 'd': /* Backward compatible. */ + style = DECOMPRESS; + break; + case 'f': + force = 1; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + usage(style == COMPRESS); + } + argc -= optind; + argv += optind; + + if (argc == 0) { + switch(style) { + case COMPRESS: + (void)compress("/dev/stdin", "/dev/stdout", bits); + break; + case DECOMPRESS: + (void)decompress("/dev/stdin", "/dev/stdout", bits); + break; + } + exit (eval); + } + + if (cat == 1 && argc > 1) + errx(1, "the -c option permits only a single file argument"); + + for (; *argv; ++argv) + switch(style) { + case COMPRESS: + if (cat) { + compress(*argv, "/dev/stdout", bits); + break; + } + if ((p = rindex(*argv, '.')) != NULL && + !strcmp(p, ".Z")) { + cwarnx("%s: name already has trailing .Z", + *argv); + break; + } + len = strlen(*argv); + if (len > sizeof(newname) - 3) { + cwarnx("%s: name too long", *argv); + break; + } + memmove(newname, *argv, len); + newname[len] = '.'; + newname[len + 1] = 'Z'; + newname[len + 2] = '\0'; + compress(*argv, newname, bits); + break; + case DECOMPRESS: + len = strlen(*argv); + if ((p = rindex(*argv, '.')) == NULL || + strcmp(p, ".Z")) { + if (len > sizeof(newname) - 3) { + cwarnx("%s: name too long", *argv); + break; + } + memmove(newname, *argv, len); + newname[len] = '.'; + newname[len + 1] = 'Z'; + newname[len + 2] = '\0'; + decompress(newname, + cat ? "/dev/stdout" : *argv, bits); + } else { + if (len - 2 > sizeof(newname) - 1) { + cwarnx("%s: name too long", *argv); + break; + } + memmove(newname, *argv, len - 2); + newname[len - 2] = '\0'; + decompress(*argv, + cat ? "/dev/stdout" : newname, bits); + } + break; + } + exit (eval); +} + +void +compress(in, out, bits) + char *in, *out; + int bits; +{ + register int nr; + struct stat isb, sb; + FILE *ifp, *ofp; + int exists, isreg, oreg; + u_char buf[1024]; + + exists = !stat(out, &sb); + if (!force && exists && S_ISREG(sb.st_mode) && !permission(out)) + return; + isreg = oreg = !exists || S_ISREG(sb.st_mode); + + ifp = ofp = NULL; + if ((ifp = fopen(in, "r")) == NULL) { + cwarn("%s", in); + return; + } + if (stat(in, &isb)) { /* DON'T FSTAT! */ + cwarn("%s", in); + goto err; + } + if (!S_ISREG(isb.st_mode)) + isreg = 0; + + if ((ofp = zopen(out, "w", bits)) == NULL) { + cwarn("%s", out); + goto err; + } + while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0) + if (fwrite(buf, 1, nr, ofp) != nr) { + cwarn("%s", out); + goto err; + } + + if (ferror(ifp) || fclose(ifp)) { + cwarn("%s", in); + goto err; + } + ifp = NULL; + + if (fclose(ofp)) { + cwarn("%s", out); + goto err; + } + ofp = NULL; + + if (isreg) { + if (stat(out, &sb)) { + cwarn("%s", out); + goto err; + } + + if (!force && sb.st_size >= isb.st_size) { + if (verbose) + (void)printf("%s: file would grow; left unmodified\n", in); + if (unlink(out)) + cwarn("%s", out); + goto err; + } + + setfile(out, &isb); + + if (unlink(in)) + cwarn("%s", in); + + if (verbose) { + (void)printf("%s: ", out); + if (isb.st_size > sb.st_size) + (void)printf("%.0f%% compression\n", + ((float)sb.st_size / isb.st_size) * 100.0); + else + (void)printf("%.0f%% expansion\n", + ((float)isb.st_size / sb.st_size) * 100.0); + } + } + return; + +err: if (ofp) { + if (oreg) + (void)unlink(out); + (void)fclose(ofp); + } + if (ifp) + (void)fclose(ifp); +} + +void +decompress(in, out, bits) + char *in, *out; + int bits; +{ + register int nr; + struct stat sb; + FILE *ifp, *ofp; + int exists, isreg, oreg; + u_char buf[1024]; + + exists = !stat(out, &sb); + if (!force && exists && S_ISREG(sb.st_mode) && !permission(out)) + return; + isreg = oreg = !exists || S_ISREG(sb.st_mode); + + ifp = ofp = NULL; + if ((ofp = fopen(out, "w")) == NULL) { + cwarn("%s", out); + return; + } + + if ((ifp = zopen(in, "r", bits)) == NULL) { + cwarn("%s", in); + goto err; + } + if (stat(in, &sb)) { + cwarn("%s", in); + goto err; + } + if (!S_ISREG(sb.st_mode)) + isreg = 0; + + while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0) + if (fwrite(buf, 1, nr, ofp) != nr) { + cwarn("%s", out); + goto err; + } + + if (ferror(ifp) || fclose(ifp)) { + cwarn("%s", in); + goto err; + } + ifp = NULL; + + if (fclose(ofp)) { + cwarn("%s", out); + goto err; + } + + if (isreg) { + setfile(out, &sb); + + if (unlink(in)) + cwarn("%s", in); + } + return; + +err: if (ofp) { + if (oreg) + (void)unlink(out); + (void)fclose(ofp); + } + if (ifp) + (void)fclose(ifp); +} + +void +setfile(name, fs) + char *name; + register struct stat *fs; +{ + static struct timeval tv[2]; + + fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; + + TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); + TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); + if (utimes(name, tv)) + cwarn("utimes: %s", name); + + /* + * Changing the ownership probably won't succeed, unless we're root + * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting + * the mode; current BSD behavior is to remove all setuid bits on + * chown. If chown fails, lose setuid/setgid bits. + */ + if (chown(name, fs->st_uid, fs->st_gid)) { + if (errno != EPERM) + cwarn("chown: %s", name); + fs->st_mode &= ~(S_ISUID|S_ISGID); + } + if (chmod(name, fs->st_mode)) + cwarn("chown: %s", name); + + if (chflags(name, fs->st_flags)) + cwarn("chflags: %s", name); +} + +int +permission(fname) + char *fname; +{ + int ch, first; + + if (!isatty(fileno(stderr))) + return (0); + (void)fprintf(stderr, "overwrite %s? ", fname); + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y'); +} + +void +usage(iscompress) + int iscompress; +{ + if (iscompress) + (void)fprintf(stderr, + "usage: compress [-cfv] [-b bits] [file ...]\n"); + else + (void)fprintf(stderr, + "usage: uncompress [-c] [-b bits] [file ...]\n"); + exit(1); +} + +void +#if __STDC__ +cwarnx(const char *fmt, ...) +#else +cwarnx(fmt, va_alist) + int eval; + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarnx(fmt, ap); + va_end(ap); + eval = 1; +} + +void +#if __STDC__ +cwarn(const char *fmt, ...) +#else +cwarn(fmt, va_alist) + int eval; + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarn(fmt, ap); + va_end(ap); + eval = 1; +} diff --git a/usr.bin/compress/doc/NOTES b/usr.bin/compress/doc/NOTES new file mode 100644 index 0000000..7c28c9c --- /dev/null +++ b/usr.bin/compress/doc/NOTES @@ -0,0 +1,139 @@ +From: James A. Woods + +>From vn Fri Dec 2 18:05:27 1988 +Subject: Re: Looking for C source for RSA +Newsgroups: sci.crypt + +# Illegitimi noncarborundum + +Patents are a tar pit. + +A good case can be made that most are just a license to sue, and nothing +is illegal until a patent is upheld in court. + +For example, if you receive netnews by means other than 'nntp', +these very words are being modulated by 'compress', +a variation on the patented Lempel-Ziv-Welch algorithm. + +Original Ziv-Lempel is patent number 4,464,650, and the more powerful +LZW method is #4,558,302. Yet despite any similarities between 'compress' +and LZW (the public-domain 'compress' code was designed and given to the +world before the ink on the Welch patent was dry), no attorneys from Sperry +(the assignee) have asked you to unplug your Usenet connection. + +Why? I can't speak for them, but it is possible the claims are too broad, +or, just as bad, not broad enough. ('compress' does things not mentioned +in the Welch patent.) Maybe they realize that they can commercialize +LZW better by selling hardware implementations rather than by licensing +software. Again, the LZW software delineated in the patent is *not* +the same as that of 'compress'. + +At any rate, court-tested software patents are a different animal; +corporate patents in a portfolio are usually traded like baseball cards +to shut out small fry rather than actually be defended before +non-technical juries. Perhaps RSA will undergo this test successfully, +although the grant to "exclude others from making, using, or selling" +the invention would then only apply to the U.S. (witness the +Genentech patent of the TPA molecule in the U.S. but struck down +in Great Britain as too broad.) + +The concept is still exotic for those who learned in school the rule of thumb +that one may patent "apparatus" but not an "idea". +Apparently this all changed in Diamond v. Diehr (1981) when the U. S. Supreme +Court reversed itself. + +Scholars should consult the excellent article in the Washington and Lee +Law Review (fall 1984, vol. 41, no. 4) by Anthony and Colwell for a +comprehensive survey of an area which will remain murky for some time. + +Until the dust clears, how you approach ideas which are patented depends +on how paranoid you are of a legal onslaught. Arbitrary? Yes. But +the patent bar the the CCPA (Court of Customs and Patent Appeals) +thanks you for any uncertainty as they, at least, stand to gain +from any trouble. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +From: James A. Woods +Subject: Re: Looking for C source for RSA (actually 'compress' patents) + + In article <2042@eos.UUCP> you write: + >The concept is still exotic for those who learned in school the rule of thumb + >that one may patent "apparatus" but not an "idea". + +A rule of thumb that has never been completely valid, as any chemical +engineer can tell you. (Chemical processes were among the earliest patents, +as I recall.) + + ah yes -- i date myself when relaying out-of-date advice from elderly + attorneys who don't even specialize in patents. one other interesting + class of patents include the output of optical lens design programs, + which yield formulae which can then fairly directly can be molded + into glass. although there are restrictions on patenting equations, + the "embedded systems" seem to fly past the legal gauntlets. + + anyway, i'm still learning about intellectual property law after + several conversations from a unisys (nee sperry) lawyer re 'compress'. + + it's more complicated than this, but they're letting (oral + communication only) software versions of 'compress' slide + as far as licensing fees go. this includes 'arc', 'stuffit', + and other commercial wrappers for 'compress'. yet they are + signing up licensees for hardware chips. hewlett-packard + supposedly has an active vlsi project, and unisys has + board-level lzw-based tape controllers. (to build lzw into + a disk controller would be strange, as you'd have to build + in a filesystem too!) + + it's byzantine + that unisys is in a tiff with hp regarding the patents, + after discovering some sort of "compress" button on some + hp terminal product. why? well, professor abraham lempel jumped + from being department chairman of computer science at technion in + israel to sperry (where he got the first patent), but then to work + at hewlett-packard on sabbatical. the second welch patent + is only weakly derivative of the first, so they want chip + licenses and hp relented. however, everyone agrees something + like the current unix implementation is the way to go with + software, so hp (and ucb) long ago asked spencer thomas and i to sign + off on copyright permission (although they didn't need to, it being pd). + lempel, hp, and unisys grumbles they can't make money off the + software since a good free implementation (not the best -- + i have more ideas!) escaped via usenet. (lempel's own pascal + code was apparently horribly slow.) + i don't follow the ibm 'arc' legal bickering; my impression + is that the pc folks are making money off the archiver/wrapper + look/feel of the thing [if ms-dos can be said to have a look and feel]. + + now where is telebit with the compress firmware? in a limbo + netherworld, probably, with sperry still welcoming outfits + to sign patent licenses, a common tactic to bring other small fry + into the fold. the guy who crammed 12-bit compess into the modem + there left. also what is transpiring with 'compress' and sys 5 rel 4? + beats me, but if sperry got a hold of them on these issues, + at&t would likely re-implement another algorithm if they + thought 'compress' infringes. needful to say, i don't think + it does after the abovementioned legal conversation. + my own beliefs on whether algorithms should be patentable at all + change with the weather. if the courts finally nail down + patent protection for algorithms, academic publication in + textbooks will be somewhat at odds with the engineering world, + where the textbook codes will simply be a big tease to get + money into the patent holder coffers... + + oh, if you implement lzw from the patent, you won't get + good rates because it doesn't mention adaptive table reset, + lack thereof being *the* serious deficiency of thomas' first version. + + now i know that patent law generally protects against independent + re-invention (like the 'xor' hash function pleasantly mentioned + in the patent [but not the paper]). + but the upshot is that if anyone ever wanted to sue us, + we're partially covered with + independently-developed twists, plus the fact that some of us work + in a bureacratic morass (as contractor to a public agency in my case). + + quite a mess, huh? i've wanted to tell someone this stuff + for a long time, for posterity if nothing else. + +james + diff --git a/usr.bin/compress/doc/README b/usr.bin/compress/doc/README new file mode 100644 index 0000000..6803287 --- /dev/null +++ b/usr.bin/compress/doc/README @@ -0,0 +1,283 @@ + + @(#)README 8.1 (Berkeley) 6/9/93 + +Compress version 4.0 improvements over 3.0: + o compress() speedup (10-50%) by changing division hash to xor + o decompress() speedup (5-10%) + o Memory requirements reduced (3-30%) + o Stack requirements reduced to less than 4kb + o Removed 'Big+Fast' compress code (FBITS) because of compress speedup + o Portability mods for Z8000 and PC/XT (but not zeus 3.2) + o Default to 'quiet' mode + o Unification of 'force' flags + o Manual page overhaul + o Portability enhancement for M_XENIX + o Removed text on #else and #endif + o Added "-V" switch to print version and options + o Added #defines for SIGNED_COMPARE_SLOW + o Added Makefile and "usermem" program + o Removed all floating point computations + o New programs: [deleted] + +The "usermem" script attempts to determine the maximum process size. Some +editing of the script may be necessary (see the comments). [It should work +fine on 4.3 bsd.] If you can't get it to work at all, just create file +"USERMEM" containing the maximum process size in decimal. + +The following preprocessor symbols control the compilation of "compress.c": + + o USERMEM Maximum process memory on the system + o SACREDMEM Amount to reserve for other proceses + o SIGNED_COMPARE_SLOW Unsigned compare instructions are faster + o NO_UCHAR Don't use "unsigned char" types + o BITS Overrules default set by USERMEM-SACREDMEM + o vax Generate inline assembler + o interdata Defines SIGNED_COMPARE_SLOW + o M_XENIX Makes arrays < 65536 bytes each + o pdp11 BITS=12, NO_UCHAR + o z8000 BITS=12 + o pcxt BITS=12 + o BSD4_2 Allow long filenames ( > 14 characters) & + Call setlinebuf(stderr) + +The difference "usermem-sacredmem" determines the maximum BITS that can be +specified with the "-b" flag. + +memory: at least BITS +------ -- ----- ---- + 433,484 16 + 229,600 15 + 127,536 14 + 73,464 13 + 0 12 + +The default is BITS=16. + +The maximum bits can be overrulled by specifying "-DBITS=bits" at +compilation time. + +WARNING: files compressed on a large machine with more bits than allowed by +a version of compress on a smaller machine cannot be decompressed! Use the +"-b12" flag to generate a file on a large machine that can be uncompressed +on a 16-bit machine. + +The output of compress 4.0 is fully compatible with that of compress 3.0. +In other words, the output of compress 4.0 may be fed into uncompress 3.0 or +the output of compress 3.0 may be fed into uncompress 4.0. + +The output of compress 4.0 not compatible with that of +compress 2.0. However, compress 4.0 still accepts the output of +compress 2.0. To generate output that is compatible with compress +2.0, use the undocumented "-C" flag. + + -from mod.sources, submitted by vax135!petsd!joe (Joe Orost), 8/1/85 +-------------------------------- + +Enclosed is compress version 3.0 with the following changes: + +1. "Block" compression is performed. After the BITS run out, the + compression ratio is checked every so often. If it is decreasing, + the table is cleared and a new set of substrings are generated. + + This makes the output of compress 3.0 not compatible with that of + compress 2.0. However, compress 3.0 still accepts the output of + compress 2.0. To generate output that is compatible with compress + 2.0, use the undocumented "-C" flag. + +2. A quiet "-q" flag has been added for use by the news system. + +3. The character chaining has been deleted and the program now uses + hashing. This improves the speed of the program, especially + during decompression. Other speed improvements have been made, + such as using putc() instead of fwrite(). + +4. A large table is used on large machines when a relatively small + number of bits is specified. This saves much time when compressing + for a 16-bit machine on a 32-bit virtual machine. Note that the + speed improvement only occurs when the input file is > 30000 + characters, and the -b BITS is less than or equal to the cutoff + described below. + +Most of these changes were made by James A. Woods (ames!jaw). Thank you +James! + +To compile compress: + + cc -O -DUSERMEM=usermem -o compress compress.c + +Where "usermem" is the amount of physical user memory available (in bytes). +If any physical memory is to be reserved for other processes, put in +"-DSACREDMEM sacredmem", where "sacredmem" is the amount to be reserved. + +The difference "usermem-sacredmem" determines the maximum BITS that can be +specified, and the cutoff bits where the large+fast table is used. + +memory: at least BITS cutoff +------ -- ----- ---- ------ + 4,718,592 16 13 + 2,621,440 16 12 + 1,572,864 16 11 + 1,048,576 16 10 + 631,808 16 -- + 329,728 15 -- + 178,176 14 -- + 99,328 13 -- + 0 12 -- + +The default memory size is 750,000 which gives a maximum BITS=16 and no +large+fast table. + +The maximum bits can be overruled by specifying "-DBITS=bits" at +compilation time. + +If your machine doesn't support unsigned characters, define "NO_UCHAR" +when compiling. + +If your machine has "int" as 16-bits, define "SHORT_INT" when compiling. + +After compilation, move "compress" to a standard executable location, such +as /usr/local. Then: + cd /usr/local + ln compress uncompress + ln compress zcat + +On machines that have a fixed stack size (such as Perkin-Elmer), set the +stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer). + +Next, install the manual (compress.l). + cp compress.l /usr/man/manl + cd /usr/man/manl + ln compress.l uncompress.l + ln compress.l zcat.l + + - or - + + cp compress.l /usr/man/man1/compress.1 + cd /usr/man/man1 + ln compress.1 uncompress.1 + ln compress.1 zcat.1 + + regards, + petsd!joe + +Here is a note from the net: + +>From hplabs!pesnta!amd!turtlevax!ken Sat Jan 5 03:35:20 1985 +Path: ames!hplabs!pesnta!amd!turtlevax!ken +From: ken@turtlevax.UUCP (Ken Turkowski) +Newsgroups: net.sources +Subject: Re: Compress release 3.0 : sample Makefile +Organization: CADLINC, Inc. @ Menlo Park, CA + +In the compress 3.0 source recently posted to mod.sources, there is a +#define variable which can be set for optimum performance on a machine +with a large amount of memory. A program (usermem) to calculate the +useable amount of physical user memory is enclosed, as well as a sample +4.2bsd Vax Makefile for compress. + +Here is the README file from the previous version of compress (2.0): + +>Enclosed is compress.c version 2.0 with the following bugs fixed: +> +>1. The packed files produced by compress are different on different +> machines and dependent on the vax sysgen option. +> The bug was in the different byte/bit ordering on the +> various machines. This has been fixed. +> +> This version is NOT compatible with the original vax posting +> unless the '-DCOMPATIBLE' option is specified to the C +> compiler. The original posting has a bug which I fixed, +> causing incompatible files. I recommend you NOT to use this +> option unless you already have a lot of packed files from +> the original posting by thomas. +>2. The exit status is not well defined (on some machines) causing the +> scripts to fail. +> The exit status is now 0,1 or 2 and is documented in +> compress.l. +>3. The function getopt() is not available in all C libraries. +> The function getopt() is no longer referenced by the +> program. +>4. Error status is not being checked on the fwrite() and fflush() calls. +> Fixed. +> +>The following enhancements have been made: +> +>1. Added facilities of "compact" into the compress program. "Pack", +> "Unpack", and "Pcat" are no longer required (no longer supplied). +>2. Installed work around for C compiler bug with "-O". +>3. Added a magic number header (\037\235). Put the bits specified +> in the file. +>4. Added "-f" flag to force overwrite of output file. +>5. Added "-c" flag and "zcat" program. 'ln compress zcat' after you +> compile. +>6. The 'uncompress' script has been deleted; simply +> 'ln compress uncompress' after you compile and it will work. +>7. Removed extra bit masking for machines that support unsigned +> characters. If your machine doesn't support unsigned characters, +> define "NO_UCHAR" when compiling. +> +>Compile "compress.c" with "-O -o compress" flags. Move "compress" to a +>standard executable location, such as /usr/local. Then: +> cd /usr/local +> ln compress uncompress +> ln compress zcat +> +>On machines that have a fixed stack size (such as Perkin-Elmer), set the +>stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer). +> +>Next, install the manual (compress.l). +> cp compress.l /usr/man/manl - or - +> cp compress.l /usr/man/man1/compress.1 +> +>Here is the README that I sent with my first posting: +> +>>Enclosed is a modified version of compress.c, along with scripts to make it +>>run identically to pack(1), unpack(1), an pcat(1). Here is what I +>>(petsd!joe) and a colleague (petsd!peora!srd) did: +>> +>>1. Removed VAX dependencies. +>>2. Changed the struct to separate arrays; saves mucho memory. +>>3. Did comparisons in unsigned, where possible. (Faster on Perkin-Elmer.) +>>4. Sorted the character next chain and changed the search to stop +>>prematurely. This saves a lot on the execution time when compressing. +>> +>>This version is totally compatible with the original version. Even though +>>lint(1) -p has no complaints about compress.c, it won't run on a 16-bit +>>machine, due to the size of the arrays. +>> +>>Here is the README file from the original author: +>> +>>>Well, with all this discussion about file compression (for news batching +>>>in particular) going around, I decided to implement the text compression +>>>algorithm described in the June Computer magazine. The author claimed +>>>blinding speed and good compression ratios. It's certainly faster than +>>>compact (but, then, what wouldn't be), but it's also the same speed as +>>>pack, and gets better compression than both of them. On 350K bytes of +>>>unix-wizards, compact took about 8 minutes of CPU, pack took about 80 +>>>seconds, and compress (herein) also took 80 seconds. But, compact and +>>>pack got about 30% compression, whereas compress got over 50%. So, I +>>>decided I had something, and that others might be interested, too. +>>> +>>>As is probably true of compact and pack (although I haven't checked), +>>>the byte order within a word is probably relevant here, but as long as +>>>you stay on a single machine type, you should be ok. (Can anybody +>>>elucidate on this?) There are a couple of asm's in the code (extv and +>>>insv instructions), so anyone porting it to another machine will have to +>>>deal with this anyway (and could probably make it compatible with Vax +>>>byte order at the same time). Anyway, I've linted the code (both with +>>>and without -p), so it should run elsewhere. Note the longs in the +>>>code, you can take these out if you reduce BITS to <= 15. +>>> +>>>Have fun, and as always, if you make good enhancements, or bug fixes, +>>>I'd like to see them. +>>> +>>>=Spencer (thomas@utah-20, {harpo,hplabs,arizona}!utah-cs!thomas) +>> +>> regards, +>> joe +>> +>>-- +>>Full-Name: Joseph M. Orost +>>UUCP: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!joe +>>US Mail: MS 313; Perkin-Elmer; 106 Apple St; Tinton Falls, NJ 07724 +>>Phone: (201) 870-5844 diff --git a/usr.bin/compress/doc/revision.log b/usr.bin/compress/doc/revision.log new file mode 100644 index 0000000..b1d8b24 --- /dev/null +++ b/usr.bin/compress/doc/revision.log @@ -0,0 +1,116 @@ +/* + * $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $ + * $Log: compress.c,v $ + * Revision 4.0 85/07/30 12:50:00 joe + * Removed ferror() calls in output routine on every output except first. + * Prepared for release to the world. + * + * Revision 3.6 85/07/04 01:22:21 joe + * Remove much wasted storage by overlaying hash table with the tables + * used by decompress: tab_suffix[1<putc] and + * added signal catcher [plus beef in writeerr()] to delete effluvia. + * + * Revision 2.0 84/08/28 22:00:00 petsd!joe + * Add check for foreground before prompting user. Insert maxbits into + * compressed file. Force file being uncompressed to end with ".Z". + * Added "-c" flag and "zcat". Prepared for release. + * + * Revision 1.10 84/08/24 18:28:00 turtlevax!ken + * Will only compress regular files (no directories), added a magic number + * header (plus an undocumented -n flag to handle old files without headers), + * added -f flag to force overwriting of possibly existing destination file, + * otherwise the user is prompted for a response. Will tack on a .Z to a + * filename if it doesn't have one when decompressing. Will only replace + * file if it was compressed. + * + * Revision 1.9 84/08/16 17:28:00 turtlevax!ken + * Removed scanargs(), getopt(), added .Z extension and unlimited number of + * filenames to compress. Flags may be clustered (-Ddvb12) or separated + * (-D -d -v -b 12), or combination thereof. Modes and other status is + * copied with copystat(). -O bug for 4.2 seems to have disappeared with + * 1.8. + * + * Revision 1.8 84/08/09 23:15:00 joe + * Made it compatible with vax version, installed jim's fixes/enhancements + * + * Revision 1.6 84/08/01 22:08:00 joe + * Sped up algorithm significantly by sorting the compress chain. + * + * Revision 1.5 84/07/13 13:11:00 srd + * Added C version of vax asm routines. Changed structure to arrays to + * save much memory. Do unsigned compares where possible (faster on + * Perkin-Elmer) + * + * Revision 1.4 84/07/05 03:11:11 thomas + * Clean up the code a little and lint it. (Lint complains about all + * the regs used in the asm, but I'm not going to "fix" this.) + * + * Revision 1.3 84/07/05 02:06:54 thomas + * Minor fixes. + * + * Revision 1.2 84/07/05 00:27:27 thomas + * Add variable bit length output. + * + */ + +static char rcs_ident[] = + "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $"; diff --git a/usr.bin/compress/zcat.sh b/usr.bin/compress/zcat.sh new file mode 100644 index 0000000..c4931e4 --- /dev/null +++ b/usr.bin/compress/zcat.sh @@ -0,0 +1,37 @@ +#!/bin/sh - +# +# 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. +# +# @(#)zcat.sh 8.1 (Berkeley) 6/6/93 +# + +uncompress -c $* diff --git a/usr.bin/compress/zopen.3 b/usr.bin/compress/zopen.3 new file mode 100644 index 0000000..853462f --- /dev/null +++ b/usr.bin/compress/zopen.3 @@ -0,0 +1,139 @@ +.\" 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. +.\" +.\" @(#)zopen.3 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt ZOPEN 3 +.Os +.Sh NAME +.Nm zopen +.Nd compressed stream open function +.Sh SYNOPSIS +.Fd #include +.Ft FILE * +.Fn zopen "const char *path" "const char *mode" "int bits" +.Sh DESCRIPTION +The +.Fn zopen +function +opens the compressed file whose name is the string pointed to by +.Fa path +and associates a stream with it. +.Pp +The argument +.Fa mode +points to one of the following one-character strings: +.Bl -tag -width indent +.It Dq Li r +Open compressed file for reading. +The stream is positioned at the beginning of the file. +.It Dq Li w +Truncate file to zero length or create compressed file for writing. +The stream is positioned at the beginning of the file. +.El +.Pp +Any created files will have mode +.Pf \\*q Dv S_IRUSR +\&| +.Dv S_IWUSR +\&| +.Dv S_IRGRP +\&| +.Dv S_IWGRP +\&| +.Dv S_IROTH +\&| +.Dv S_IWOTH Ns \\*q +.Pq Li 0666 , +as modified by the process' +umask value (see +.Xr umask 2 ) . +.Pp +Files may only be read or written. +Seek operations are not allowed. +.Pp +The +.Fa bits +argument, if non-zero, is set to the bits code limit. +If zero, the default is 16. +See +.Fn compress 1 +for more information. +.Sh RETURN VALUES +Upon successful completion +.Fn zopen +returns a +.Tn FILE +pointer. +Otherwise, +.Dv NULL +is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +.Bl -tag -width [EINVAL] +.It Bq Er EINVAL +The +.Fa mode +or +.Fa bits +arguments specified to +.Fn zopen +were invalid. +.It Bq Er EFTYPE +The compressed file starts with an invalid header, or the compressed +file is compressed with more bits than can be handled. +.El +.Pp +The +.Fn zopen +function may also fail and set +.Va errno +for any of the errors specified for the routines +.Xr fopen 3 +or +.Xr funopen 3 . +.Sh SEE ALSO +.Xr compress 1 , +.Xr fopen 3 , +.Xr funopen 3 +.Sh HISTORY +The +.Nm zopen +function +first appeared in 4.4BSD. +.Sh BUGS +The +.Fn zopen +function +may not be portable to systems other than +.Bx . diff --git a/usr.bin/compress/zopen.c b/usr.bin/compress/zopen.c new file mode 100644 index 0000000..b76fca6 --- /dev/null +++ b/usr.bin/compress/zopen.c @@ -0,0 +1,740 @@ +/*- + * Copyright (c) 1985, 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis and James A. Woods, derived from original + * work by Spencer Thomas and Joseph Orost. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)zopen.c 8.1 (Berkeley) 6/27/93"; +#endif /* LIBC_SCCS and not lint */ + +/*- + * fcompress.c - File compression ala IEEE Computer, June 1984. + * + * Compress authors: + * Spencer W. Thomas (decvax!utah-cs!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + * + * Cleaned up and converted to library returning I/O streams by + * Diomidis Spinellis . + * + * zopen(filename, mode, bits) + * Returns a FILE * that can be used for read or write. The modes + * supported are only "r" and "w". Seeking is not allowed. On + * reading the file is decompressed, on writing it is compressed. + * The output is compatible with compress(1) with 16 bit tables. + * Any file produced by compress(1) can be read. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define BITS 16 /* Default bits. */ +#define HSIZE 69001 /* 95% occupancy */ + +/* A code_int must be able to hold 2**BITS values of type int, and also -1. */ +typedef long code_int; +typedef long count_int; + +typedef u_char char_type; +static char_type magic_header[] = + {'\037', '\235'}; /* 1F 9D */ + +#define BIT_MASK 0x1f /* Defines for third byte of header. */ +#define BLOCK_MASK 0x80 + +/* + * Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is + * a fourth header byte (for expansion). + */ +#define INIT_BITS 9 /* Initial number of bits/code. */ + +#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) + +struct s_zstate { + FILE *zs_fp; /* File stream for I/O */ + char zs_mode; /* r or w */ + enum { + S_START, S_MIDDLE, S_EOF + } zs_state; /* State of computation */ + int zs_n_bits; /* Number of bits/code. */ + int zs_maxbits; /* User settable max # bits/code. */ + code_int zs_maxcode; /* Maximum code, given n_bits. */ + code_int zs_maxmaxcode; /* Should NEVER generate this code. */ + count_int zs_htab [HSIZE]; + u_short zs_codetab [HSIZE]; + code_int zs_hsize; /* For dynamic table sizing. */ + code_int zs_free_ent; /* First unused entry. */ + /* + * Block compression parameters -- after all codes are used up, + * and compression rate changes, start over. + */ + int zs_block_compress; + int zs_clear_flg; + long zs_ratio; + count_int zs_checkpoint; + int zs_offset; + long zs_in_count; /* Length of input. */ + long zs_bytes_out; /* Length of compressed output. */ + long zs_out_count; /* # of codes output (for debugging). */ + char_type zs_buf[BITS]; + union { + struct { + long zs_fcode; + code_int zs_ent; + code_int zs_hsize_reg; + int zs_hshift; + } w; /* Write paramenters */ + struct { + char_type *zs_stackp; + int zs_finchar; + code_int zs_code, zs_oldcode, zs_incode; + int zs_roffset, zs_size; + char_type zs_gbuf[BITS]; + } r; /* Read parameters */ + } u; +}; + +/* Definitions to retain old variable names */ +#define fp zs->zs_fp +#define zmode zs->zs_mode +#define state zs->zs_state +#define n_bits zs->zs_n_bits +#define maxbits zs->zs_maxbits +#define maxcode zs->zs_maxcode +#define maxmaxcode zs->zs_maxmaxcode +#define htab zs->zs_htab +#define codetab zs->zs_codetab +#define hsize zs->zs_hsize +#define free_ent zs->zs_free_ent +#define block_compress zs->zs_block_compress +#define clear_flg zs->zs_clear_flg +#define ratio zs->zs_ratio +#define checkpoint zs->zs_checkpoint +#define offset zs->zs_offset +#define in_count zs->zs_in_count +#define bytes_out zs->zs_bytes_out +#define out_count zs->zs_out_count +#define buf zs->zs_buf +#define fcode zs->u.w.zs_fcode +#define hsize_reg zs->u.w.zs_hsize_reg +#define ent zs->u.w.zs_ent +#define hshift zs->u.w.zs_hshift +#define stackp zs->u.r.zs_stackp +#define finchar zs->u.r.zs_finchar +#define code zs->u.r.zs_code +#define oldcode zs->u.r.zs_oldcode +#define incode zs->u.r.zs_incode +#define roffset zs->u.r.zs_roffset +#define size zs->u.r.zs_size +#define gbuf zs->u.r.zs_gbuf + +/* + * To save much memory, we overlay the table used by compress() with those + * used by decompress(). The tab_prefix table is the same size and type as + * the codetab. The tab_suffix table needs 2**BITS characters. We get this + * from the beginning of htab. The output stack uses the rest of htab, and + * contains characters. There is plenty of room for any possible stack + * (stack used to be 8000 characters). + */ + +#define htabof(i) htab[i] +#define codetabof(i) codetab[i] + +#define tab_prefixof(i) codetabof(i) +#define tab_suffixof(i) ((char_type *)(htab))[i] +#define de_stack ((char_type *)&tab_suffixof(1 << BITS)) + +#define CHECK_GAP 10000 /* Ratio check interval. */ + +/* + * the next two codes should not be changed lightly, as they must not + * lie within the contiguous general code space. + */ +#define FIRST 257 /* First free entry. */ +#define CLEAR 256 /* Table clear output code. */ + +static int cl_block __P((struct s_zstate *)); +static void cl_hash __P((struct s_zstate *, count_int)); +static code_int getcode __P((struct s_zstate *)); +static int output __P((struct s_zstate *, code_int)); +static int zclose __P((void *)); +static int zread __P((void *, char *, int)); +static int zwrite __P((void *, const char *, int)); + +/*- + * Algorithm from "A Technique for High Performance Data Compression", + * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19. + * + * Algorithm: + * Modified Lempel-Ziv method (LZW). Basically finds common + * substrings and replaces them with a variable size code. This is + * deterministic, and can be done on the fly. Thus, the decompression + * procedure needs no input table, but tracks the way the table was built. + */ + +/*- + * compress write + * + * Algorithm: use open addressing double hashing (no chaining) on the + * prefix code / next character combination. We do a variant of Knuth's + * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime + * secondary probe. Here, the modular division first probe is gives way + * to a faster exclusive-or manipulation. Also do block compression with + * an adaptive reset, whereby the code table is cleared when the compression + * ratio decreases, but after the table fills. The variable-length output + * codes are re-sized at this point, and a special CLEAR code is generated + * for the decompressor. Late addition: construct the table according to + * file size for noticeable speed improvement on small files. Please direct + * questions about this implementation to ames!jaw. + */ +static int +zwrite(cookie, wbp, num) + void *cookie; + const char *wbp; + int num; +{ + register code_int i; + register int c, disp; + struct s_zstate *zs; + const u_char *bp; + u_char tmp; + int count; + + if (num == 0) + return (0); + + zs = cookie; + count = num; + bp = (u_char *)wbp; + if (state == S_MIDDLE) + goto middle; + state = S_MIDDLE; + + maxmaxcode = 1L << BITS; + if (fwrite(magic_header, + sizeof(char), sizeof(magic_header), fp) != sizeof(magic_header)) + return (-1); + tmp = (u_char)(BITS | block_compress); + if (fwrite(&tmp, sizeof(char), sizeof(tmp), fp) != sizeof(tmp)) + return (-1); + + offset = 0; + bytes_out = 3; /* Includes 3-byte header mojo. */ + out_count = 0; + clear_flg = 0; + ratio = 0; + in_count = 1; + checkpoint = CHECK_GAP; + maxcode = MAXCODE(n_bits = INIT_BITS); + free_ent = ((block_compress) ? FIRST : 256); + + ent = *bp++; + --count; + + hshift = 0; + for (fcode = (long)hsize; fcode < 65536L; fcode *= 2L) + hshift++; + hshift = 8 - hshift; /* Set hash code range bound. */ + + hsize_reg = hsize; + cl_hash(zs, (count_int)hsize_reg); /* Clear hash table. */ + +middle: for (i = 0; count--;) { + c = *bp++; + in_count++; + fcode = (long)(((long)c << maxbits) + ent); + i = ((c << hshift) ^ ent); /* Xor hashing. */ + + if (htabof(i) == fcode) { + ent = codetabof(i); + continue; + } else if ((long)htabof(i) < 0) /* Empty slot. */ + goto nomatch; + disp = hsize_reg - i; /* Secondary hash (after G. Knott). */ + if (i == 0) + disp = 1; +probe: if ((i -= disp) < 0) + i += hsize_reg; + + if (htabof(i) == fcode) { + ent = codetabof(i); + continue; + } + if ((long)htabof(i) >= 0) + goto probe; +nomatch: if (output(zs, (code_int) ent) == -1) + return (-1); + out_count++; + ent = c; + if (free_ent < maxmaxcode) { + codetabof(i) = free_ent++; /* code -> hashtable */ + htabof(i) = fcode; + } else if ((count_int)in_count >= + checkpoint && block_compress) { + if (cl_block(zs) == -1) + return (-1); + } + } + return (num); +} + +static int +zclose(cookie) + void *cookie; +{ + struct s_zstate *zs; + int rval; + + zs = cookie; + if (zmode == 'w') { /* Put out the final code. */ + if (output(zs, (code_int) ent) == -1) { + (void)fclose(fp); + free(zs); + return (-1); + } + out_count++; + if (output(zs, (code_int) - 1) == -1) { + (void)fclose(fp); + free(zs); + return (-1); + } + } + rval = fclose(fp) == EOF ? -1 : 0; + free(zs); + return (rval); +} + +/*- + * Output the given code. + * Inputs: + * code: A n_bits-bit integer. If == -1, then EOF. This assumes + * that n_bits =< (long)wordsize - 1. + * Outputs: + * Outputs code to the file. + * Assumptions: + * Chars are 8 bits long. + * Algorithm: + * Maintain a BITS character long buffer (so that 8 codes will + * fit in it exactly). Use the VAX insv instruction to insert each + * code in turn. When the buffer fills up empty it and start over. + */ + +static char_type lmask[9] = + {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; +static char_type rmask[9] = + {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + +static int +output(zs, ocode) + struct s_zstate *zs; + code_int ocode; +{ + register int bits, r_off; + register char_type *bp; + + r_off = offset; + bits = n_bits; + bp = buf; + if (ocode >= 0) { + /* Get to the first byte. */ + bp += (r_off >> 3); + r_off &= 7; + /* + * Since ocode is always >= 8 bits, only need to mask the first + * hunk on the left. + */ + *bp = (*bp & rmask[r_off]) | (ocode << r_off) & lmask[r_off]; + bp++; + bits -= (8 - r_off); + ocode >>= 8 - r_off; + /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ + if (bits >= 8) { + *bp++ = ocode; + ocode >>= 8; + bits -= 8; + } + /* Last bits. */ + if (bits) + *bp = ocode; + offset += n_bits; + if (offset == (n_bits << 3)) { + bp = buf; + bits = n_bits; + bytes_out += bits; + if (fwrite(bp, sizeof(char), bits, fp) != bits) + return (-1); + bp += bits; + bits = 0; + offset = 0; + } + /* + * If the next entry is going to be too big for the ocode size, + * then increase it, if possible. + */ + if (free_ent > maxcode || (clear_flg > 0)) { + /* + * Write the whole buffer, because the input side won't + * discover the size increase until after it has read it. + */ + if (offset > 0) { + if (fwrite(buf, 1, n_bits, fp) != n_bits) + return (-1); + bytes_out += n_bits; + } + offset = 0; + + if (clear_flg) { + maxcode = MAXCODE(n_bits = INIT_BITS); + clear_flg = 0; + } else { + n_bits++; + if (n_bits == maxbits) + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } + } + } else { + /* At EOF, write the rest of the buffer. */ + if (offset > 0) { + offset = (offset + 7) / 8; + if (fwrite(buf, 1, offset, fp) != offset) + return (-1); + bytes_out += offset; + } + offset = 0; + } + return (0); +} + +/* + * Decompress read. This routine adapts to the codes in the file building + * the "string" table on-the-fly; requiring no table to be stored in the + * compressed file. The tables used herein are shared with those of the + * compress() routine. See the definitions above. + */ +static int +zread(cookie, rbp, num) + void *cookie; + char *rbp; + int num; +{ + register u_int count; + struct s_zstate *zs; + u_char *bp, header[3]; + + if (num == 0) + return (0); + + zs = cookie; + count = num; + bp = (u_char *)rbp; + switch (state) { + case S_START: + state = S_MIDDLE; + break; + case S_MIDDLE: + goto middle; + case S_EOF: + goto eof; + } + + /* Check the magic number */ + if (fread(header, + sizeof(char), sizeof(header), fp) != sizeof(header) || + memcmp(header, magic_header, sizeof(magic_header)) != 0) { + errno = EFTYPE; + return (-1); + } + maxbits = header[2]; /* Set -b from file. */ + block_compress = maxbits & BLOCK_MASK; + maxbits &= BIT_MASK; + maxmaxcode = 1L << maxbits; + if (maxbits > BITS) { + errno = EFTYPE; + return (-1); + } + /* As above, initialize the first 256 entries in the table. */ + maxcode = MAXCODE(n_bits = INIT_BITS); + for (code = 255; code >= 0; code--) { + tab_prefixof(code) = 0; + tab_suffixof(code) = (char_type) code; + } + free_ent = block_compress ? FIRST : 256; + + finchar = oldcode = getcode(zs); + if (oldcode == -1) /* EOF already? */ + return (0); /* Get out of here */ + + /* First code must be 8 bits = char. */ + *bp++ = (u_char)finchar; + count--; + stackp = de_stack; + + while ((code = getcode(zs)) > -1) { + + if ((code == CLEAR) && block_compress) { + for (code = 255; code >= 0; code--) + tab_prefixof(code) = 0; + clear_flg = 1; + free_ent = FIRST - 1; + if ((code = getcode(zs)) == -1) /* O, untimely death! */ + break; + } + incode = code; + + /* Special case for KwKwK string. */ + if (code >= free_ent) { + *stackp++ = finchar; + code = oldcode; + } + + /* Generate output characters in reverse order. */ + while (code >= 256) { + *stackp++ = tab_suffixof(code); + code = tab_prefixof(code); + } + *stackp++ = finchar = tab_suffixof(code); + + /* And put them out in forward order. */ +middle: do { + if (count-- == 0) + return (num); + *bp++ = *--stackp; + } while (stackp > de_stack); + + /* Generate the new entry. */ + if ((code = free_ent) < maxmaxcode) { + tab_prefixof(code) = (u_short) oldcode; + tab_suffixof(code) = finchar; + free_ent = code + 1; + } + + /* Remember previous code. */ + oldcode = incode; + } + state = S_EOF; +eof: return (num - count); +} + +/*- + * Read one code from the standard input. If EOF, return -1. + * Inputs: + * stdin + * Outputs: + * code or -1 is returned. + */ +static code_int +getcode(zs) + struct s_zstate *zs; +{ + register code_int gcode; + register int r_off, bits; + register char_type *bp; + + bp = gbuf; + if (clear_flg > 0 || roffset >= size || free_ent > maxcode) { + /* + * If the next entry will be too big for the current gcode + * size, then we must increase the size. This implies reading + * a new buffer full, too. + */ + if (free_ent > maxcode) { + n_bits++; + if (n_bits == maxbits) /* Won't get any bigger now. */ + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } + if (clear_flg > 0) { + maxcode = MAXCODE(n_bits = INIT_BITS); + clear_flg = 0; + } + size = fread(gbuf, 1, n_bits, fp); + if (size <= 0) /* End of file. */ + return (-1); + roffset = 0; + /* Round size down to integral number of codes. */ + size = (size << 3) - (n_bits - 1); + } + r_off = roffset; + bits = n_bits; + + /* Get to the first byte. */ + bp += (r_off >> 3); + r_off &= 7; + + /* Get first part (low order bits). */ + gcode = (*bp++ >> r_off); + bits -= (8 - r_off); + r_off = 8 - r_off; /* Now, roffset into gcode word. */ + + /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ + if (bits >= 8) { + gcode |= *bp++ << r_off; + r_off += 8; + bits -= 8; + } + + /* High order bits. */ + gcode |= (*bp & rmask[bits]) << r_off; + roffset += n_bits; + + return (gcode); +} + +static int +cl_block(zs) /* Table clear for block compress. */ + struct s_zstate *zs; +{ + register long rat; + + checkpoint = in_count + CHECK_GAP; + + if (in_count > 0x007fffff) { /* Shift will overflow. */ + rat = bytes_out >> 8; + if (rat == 0) /* Don't divide by zero. */ + rat = 0x7fffffff; + else + rat = in_count / rat; + } else + rat = (in_count << 8) / bytes_out; /* 8 fractional bits. */ + if (rat > ratio) + ratio = rat; + else { + ratio = 0; + cl_hash(zs, (count_int) hsize); + free_ent = FIRST; + clear_flg = 1; + if (output(zs, (code_int) CLEAR) == -1) + return (-1); + } + return (0); +} + +static void +cl_hash(zs, cl_hsize) /* Reset code table. */ + struct s_zstate *zs; + register count_int cl_hsize; +{ + register count_int *htab_p; + register long i, m1; + + m1 = -1; + htab_p = htab + cl_hsize; + i = cl_hsize - 16; + do { /* Might use Sys V memset(3) here. */ + *(htab_p - 16) = m1; + *(htab_p - 15) = m1; + *(htab_p - 14) = m1; + *(htab_p - 13) = m1; + *(htab_p - 12) = m1; + *(htab_p - 11) = m1; + *(htab_p - 10) = m1; + *(htab_p - 9) = m1; + *(htab_p - 8) = m1; + *(htab_p - 7) = m1; + *(htab_p - 6) = m1; + *(htab_p - 5) = m1; + *(htab_p - 4) = m1; + *(htab_p - 3) = m1; + *(htab_p - 2) = m1; + *(htab_p - 1) = m1; + htab_p -= 16; + } while ((i -= 16) >= 0); + for (i += 16; i > 0; i--) + *--htab_p = m1; +} + +FILE * +zopen(fname, mode, bits) + const char *fname, *mode; + int bits; +{ + struct s_zstate *zs; + + if (mode[0] != 'r' && mode[0] != 'w' || mode[1] != '\0' || + bits < 0 || bits > BITS) { + errno = EINVAL; + return (NULL); + } + + if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL) + return (NULL); + + maxbits = bits ? bits : BITS; /* User settable max # bits/code. */ + maxmaxcode = 1 << BITS; /* Should NEVER generate this code. */ + hsize = HSIZE; /* For dynamic table sizing. */ + free_ent = 0; /* First unused entry. */ + block_compress = BLOCK_MASK; + clear_flg = 0; + ratio = 0; + checkpoint = CHECK_GAP; + in_count = 1; /* Length of input. */ + out_count = 0; /* # of codes output (for debugging). */ + state = S_START; + roffset = 0; + size = 0; + + /* + * Layering compress on top of stdio in order to provide buffering, + * and ensure that reads and write work with the data specified. + */ + if ((fp = fopen(fname, mode)) == NULL) { + free(zs); + return (NULL); + } + switch (*mode) { + case 'r': + zmode = 'r'; + return (funopen(zs, zread, NULL, NULL, zclose)); + case 'w': + zmode = 'w'; + return (funopen(zs, NULL, zwrite, NULL, zclose)); + } + /* NOTREACHED */ +} diff --git a/usr.bin/cpp/Makefile b/usr.bin/cpp/Makefile new file mode 100644 index 0000000..645fb42 --- /dev/null +++ b/usr.bin/cpp/Makefile @@ -0,0 +1,17 @@ +# @(#)Makefile 8.1 (Berkeley) 7/9/93 + +NOMAN=noman +NOOBJ=noobj + +all nologin clean cleandir depend lint tags: + +beforeinstall: +.if ${MACHINE} == "sparc" + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/cpp.notraditional.sh ${DESTDIR}/usr/bin/cpp +.else + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/cpp.sh ${DESTDIR}/usr/bin/cpp +.endif + +.include diff --git a/usr.bin/cpp/cpp.notraditional.sh b/usr.bin/cpp/cpp.notraditional.sh new file mode 100644 index 0000000..b30624c --- /dev/null +++ b/usr.bin/cpp/cpp.notraditional.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# Copyright (c) 1990, 1993 +# 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. +# +# @(#)cpp.sh 8.1 (Berkeley) 6/6/93 +# +# 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/gcc2/cpp +ALST="-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/usr.bin/cpp/cpp.sh b/usr.bin/cpp/cpp.sh new file mode 100644 index 0000000..08496ab --- /dev/null +++ b/usr.bin/cpp/cpp.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# Copyright (c) 1990, 1993 +# 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. +# +# @(#)cpp.sh 8.1 (Berkeley) 6/6/93 +# +# 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/gcc2/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/usr.bin/ctags/C.c b/usr.bin/ctags/C.c new file mode 100644 index 0000000..de83f78 --- /dev/null +++ b/usr.bin/ctags/C.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)C.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +#include "ctags.h" + +static int func_entry __P((void)); +static void hash_entry __P((void)); +static void skip_string __P((int)); +static int str_entry __P((int)); + +/* + * c_entries -- + * read .c and .h files and call appropriate routines + */ +void +c_entries() +{ + int c; /* current character */ + int level; /* brace level */ + int token; /* if reading a token */ + int t_def; /* if reading a typedef */ + int t_level; /* typedef's brace level */ + char *sp; /* buffer pointer */ + char tok[MAXTOKEN]; /* token buffer */ + + lineftell = ftell(inf); + sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1; + while (GETC(!=, EOF)) { + switch (c) { + /* + * Here's where it DOESN'T handle: { + * foo(a) + * { + * #ifdef notdef + * } + * #endif + * if (a) + * puts("hello, world"); + * } + */ + case '{': + ++level; + goto endtok; + case '}': + /* + * if level goes below zero, try and fix + * it, even though we've already messed up + */ + if (--level < 0) + level = 0; + goto endtok; + + case '\n': + SETLINE; + /* + * the above 3 cases are similar in that they + * are special characters that also end tokens. + */ + endtok: if (sp > tok) { + *sp = EOS; + token = YES; + sp = tok; + } + else + token = NO; + continue; + + /* + * We ignore quoted strings and character constants + * completely. + */ + case '"': + case '\'': + (void)skip_string(c); + break; + + /* + * comments can be fun; note the state is unchanged after + * return, in case we found: + * "foo() XX comment XX { int bar; }" + */ + case '/': + if (GETC(==, '*')) { + skip_comment(); + continue; + } + (void)ungetc(c, inf); + c = '/'; + goto storec; + + /* hash marks flag #define's. */ + case '#': + if (sp == tok) { + hash_entry(); + break; + } + goto storec; + + /* + * if we have a current token, parenthesis on + * level zero indicates a function. + */ + case '(': + if (!level && token) { + int curline; + + if (sp != tok) + *sp = EOS; + /* + * grab the line immediately, we may + * already be wrong, for example, + * foo\n + * (arg1, + */ + getline(); + curline = lineno; + if (func_entry()) { + ++level; + pfnote(tok, curline); + } + break; + } + goto storec; + + /* + * semi-colons indicate the end of a typedef; if we find a + * typedef we search for the next semi-colon of the same + * level as the typedef. Ignoring "structs", they are + * tricky, since you can find: + * + * "typedef long time_t;" + * "typedef unsigned int u_int;" + * "typedef unsigned int u_int [10];" + * + * If looking at a typedef, we save a copy of the last token + * found. Then, when we find the ';' we take the current + * token if it starts with a valid token name, else we take + * the one we saved. There's probably some reasonable + * alternative to this... + */ + case ';': + if (t_def && level == t_level) { + t_def = NO; + getline(); + if (sp != tok) + *sp = EOS; + pfnote(tok, lineno); + break; + } + goto storec; + + /* + * store characters until one that can't be part of a token + * comes along; check the current token against certain + * reserved words. + */ + default: + storec: if (!intoken(c)) { + if (sp == tok) + break; + *sp = EOS; + if (tflag) { + /* no typedefs inside typedefs */ + if (!t_def && + !memcmp(tok, "typedef",8)) { + t_def = YES; + t_level = level; + break; + } + /* catch "typedef struct" */ + if ((!t_def || t_level < level) + && (!memcmp(tok, "struct", 7) + || !memcmp(tok, "union", 6) + || !memcmp(tok, "enum", 5))) { + /* + * get line immediately; + * may change before '{' + */ + getline(); + if (str_entry(c)) + ++level; + break; + /* } */ + } + } + sp = tok; + } + else if (sp != tok || begtoken(c)) { + *sp++ = c; + token = YES; + } + continue; + } + + sp = tok; + token = NO; + } +} + +/* + * func_entry -- + * handle a function reference + */ +static int +func_entry() +{ + int c; /* current character */ + int level = 0; /* for matching '()' */ + + /* + * Find the end of the assumed function declaration. + * Note that ANSI C functions can have type definitions so keep + * track of the parentheses nesting level. + */ + while (GETC(!=, EOF)) { + switch (c) { + case '\'': + case '"': + /* skip strings and character constants */ + skip_string(c); + break; + case '/': + /* skip comments */ + if (GETC(==, '*')) + skip_comment(); + break; + case '(': + level++; + break; + case ')': + if (level == 0) + goto fnd; + level--; + break; + case '\n': + SETLINE; + } + } + return (NO); +fnd: + /* + * we assume that the character after a function's right paren + * is a token character if it's a function and a non-token + * character if it's a declaration. Comments don't count... + */ + for (;;) { + while (GETC(!=, EOF) && iswhite(c)) + if (c == '\n') + SETLINE; + if (intoken(c) || c == '{') + break; + if (c == '/' && GETC(==, '*')) + skip_comment(); + else { /* don't ever "read" '/' */ + (void)ungetc(c, inf); + return (NO); + } + } + if (c != '{') + (void)skip_key('{'); + return (YES); +} + +/* + * hash_entry -- + * handle a line starting with a '#' + */ +static void +hash_entry() +{ + int c; /* character read */ + int curline; /* line started on */ + char *sp; /* buffer pointer */ + char tok[MAXTOKEN]; /* storage buffer */ + + curline = lineno; + for (sp = tok;;) { /* get next token */ + if (GETC(==, EOF)) + return; + if (iswhite(c)) + break; + *sp++ = c; + } + *sp = EOS; + if (memcmp(tok, "define", 6)) /* only interested in #define's */ + goto skip; + for (;;) { /* this doesn't handle "#define \n" */ + if (GETC(==, EOF)) + return; + if (!iswhite(c)) + break; + } + for (sp = tok;;) { /* get next token */ + *sp++ = c; + if (GETC(==, EOF)) + return; + /* + * this is where it DOESN'T handle + * "#define \n" + */ + if (!intoken(c)) + break; + } + *sp = EOS; + if (dflag || c == '(') { /* only want macros */ + getline(); + pfnote(tok, curline); + } +skip: if (c == '\n') { /* get rid of rest of define */ + SETLINE + if (*(sp - 1) != '\\') + return; + } + (void)skip_key('\n'); +} + +/* + * str_entry -- + * handle a struct, union or enum entry + */ +static int +str_entry(c) + int c; /* current character */ +{ + int curline; /* line started on */ + char *sp; /* buffer pointer */ + char tok[LINE_MAX]; /* storage buffer */ + + curline = lineno; + while (iswhite(c)) + if (GETC(==, EOF)) + return (NO); + if (c == '{') /* it was "struct {" */ + return (YES); + for (sp = tok;;) { /* get next token */ + *sp++ = c; + if (GETC(==, EOF)) + return (NO); + if (!intoken(c)) + break; + } + switch (c) { + case '{': /* it was "struct foo{" */ + --sp; + break; + case '\n': /* it was "struct foo\n" */ + SETLINE; + /*FALLTHROUGH*/ + default: /* probably "struct foo " */ + while (GETC(!=, EOF)) + if (!iswhite(c)) + break; + if (c != '{') { + (void)ungetc(c, inf); + return (NO); + } + } + *sp = EOS; + pfnote(tok, curline); + return (YES); +} + +/* + * skip_comment -- + * skip over comment + */ +void +skip_comment() +{ + int c; /* character read */ + int star; /* '*' flag */ + + for (star = 0; GETC(!=, EOF);) + switch(c) { + /* comments don't nest, nor can they be escaped. */ + case '*': + star = YES; + break; + case '/': + if (star) + return; + break; + case '\n': + SETLINE; + /*FALLTHROUGH*/ + default: + star = NO; + break; + } +} + +/* + * skip_string -- + * skip to the end of a string or character constant. + */ +void +skip_string(key) + int key; +{ + int c, + skip; + + for (skip = NO; GETC(!=, EOF); ) + switch (c) { + case '\\': /* a backslash escapes anything */ + skip = !skip; /* we toggle in case it's "\\" */ + break; + case '\n': + SETLINE; + /*FALLTHROUGH*/ + default: + if (c == key && !skip) + return; + skip = NO; + } +} + +/* + * skip_key -- + * skip to next char "key" + */ +int +skip_key(key) + int key; +{ + int c, + skip, + retval; + + for (skip = retval = NO; GETC(!=, EOF);) + switch(c) { + case '\\': /* a backslash escapes anything */ + skip = !skip; /* we toggle in case it's "\\" */ + break; + case ';': /* special case for yacc; if one */ + case '|': /* of these chars occurs, we may */ + retval = YES; /* have moved out of the rule */ + break; /* not used by C */ + case '\'': + case '"': + /* skip strings and character constants */ + skip_string(c); + break; + case '/': + /* skip comments */ + if (GETC(==, '*')) { + skip_comment(); + break; + } + (void)ungetc(c, inf); + c = '/'; + goto norm; + case '\n': + SETLINE; + /*FALLTHROUGH*/ + default: + norm: + if (c == key && !skip) + return (retval); + skip = NO; + } + return (retval); +} diff --git a/usr.bin/ctags/Makefile b/usr.bin/ctags/Makefile new file mode 100644 index 0000000..7a8ebce --- /dev/null +++ b/usr.bin/ctags/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ctags +CFLAGS+=-I${.CURDIR} +SRCS= C.c ctags.c fortran.c lisp.c print.c tree.c yacc.c + +.include diff --git a/usr.bin/ctags/ctags.1 b/usr.bin/ctags/ctags.1 new file mode 100644 index 0000000..d11dbbd --- /dev/null +++ b/usr.bin/ctags/ctags.1 @@ -0,0 +1,214 @@ +.\" Copyright (c) 1987, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ctags.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt CTAGS 1 +.Os BSD 4 +.Sh NAME +.Nm ctags +.Nd create a tags file +.Sh SYNOPSIS +.Nm ctags +.Op Fl BFadtuwvx +.Op Fl f Ar tagsfile +.Ar name ... +.Sh DESCRIPTION +.Nm Ctags +makes a tags file for +.Xr ex 1 +from the specified C, +Pascal, Fortran, +.Tn YACC , +lex, and lisp sources. +A tags file gives the locations of specified objects in a group of files. +Each line of the tags file contains the object name, the file in which it +is defined, and a search pattern for the object definition, separated by +white-space. +Using the +.Ar tags +file, +.Xr ex 1 +can quickly locate these object definitions. +Depending upon the options provided to +.Nm ctags , +objects will consist of subroutines, typedefs, defines, structs, +enums and unions. +.Bl -tag -width Ds +.It Fl B +use backward searching patterns +.Pq Li ?...? . +.It Fl F +use forward searching patterns +.Pq Li /.../ +(the default). +.It Fl a +append to +.Ar tags +file. +.It Fl d +create tags for +.Li #defines +that don't take arguments; +.Li #defines +that take arguments are tagged automatically. +.It Fl f +Places the tag descriptions in a file called +.Ar tagsfile . +The default behaviour is to place them in a file called +.Ar tags . +.It Fl t +create tags for typedefs, structs, unions, and enums. +.It Fl u +update the specified files in the +.Ar tags +file, that is, all +references to them are deleted, and the new values are appended to the +file. (Beware: this option is implemented in a way which is rather +slow; it is usually faster to simply rebuild the +.Ar tags +file.) +.It Fl v +An index of the form expected by +.Xr vgrind 1 +is produced on the standard output. This listing +contains the object name, file name, and page number (assuming 64 +line pages). Since the output will be sorted into lexicographic order, +it may be desired to run the output through +.Xr sort 1 . +Sample use: +.Bd -literal -offset indent +ctags \-v files \&| sort \-f > index +vgrind \-x index +.Ed +.It Fl w +suppress warning diagnostics. +.It Fl x +.Nm ctags +produces a list of object +names, the line number and file name on which each is defined, as well +as the text of that line and prints this on the standard output. This +is a simple index which can be printed out as an off-line readable +function index. +.El +.Pp +Files whose names end in +.Nm \&.c +or +.Nm \&.h +are assumed to be C +source files and are searched for C style routine and macro definitions. +Files whose names end in +.Nm \&.y +are assumed to be +.Tn YACC +source files. +Files whose names end in +.Nm \&.l +are assumed to be lisp files if their +first non-blank character is `;', `(', or `[', +otherwise, they are +treated as lex files. Other files are first examined to see if they +contain any Pascal or Fortran routine definitions, and, if not, are +searched for C style definitions. +.Pp +The tag +.Li main +is treated specially in C programs. The tag formed +is created by prepending +.Ar M +to the name of the file, with the +trailing +.Nm \&.c +and any leading pathname components removed. This +makes use of +.Nm ctags +practical in directories with more than one +program. +.Pp +Yacc and lex files each have a special tag. +.Ar Yyparse +is the start +of the second section of the yacc file, and +.Ar yylex +is the start of +the second section of the lex file. +.Sh FILES +.Bl -tag -width tags -compact +.It Pa tags +default output tags file +.El +.Sh DIAGNOSTICS +.Nm Ctags +exits with a value of 1 if an error occurred, 0 otherwise. +Duplicate objects are not considered errors. +.Sh SEE ALSO +.Xr ex 1 , +.Xr vi 1 +.Sh BUGS +Recognition of +.Nm functions , +.Nm subroutines +and +.Nm procedures +for +.Tn FORTRAN +and Pascal is done is a very simpleminded way. No attempt +is made to deal with block structure; if you have two Pascal procedures +in different blocks with the same name you lose. +.Nm Ctags +doesn't +understand about Pascal types. +.Pp +The method of deciding whether to look for C, Pascal or +.Tn FORTRAN +functions is a hack. +.Pp +.Nm Ctags +relies on the input being well formed, and any syntactical +errors will completely confuse it. It also finds some legal syntax +confusing; for example, since it doesn't understand +.Li #ifdef Ns 's +(incidentally, that's a feature, not a bug), any code with unbalanced +braces inside +.Li #ifdef Ns 's +will cause it to become somewhat disoriented. +In a similar fashion, multiple line changes within a definition will +cause it to enter the last line of the object, rather than the first, as +the searching pattern. The last line of multiple line +.Li typedef Ns 's +will similarly be noted. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/ctags/ctags.c b/usr.bin/ctags/ctags.c new file mode 100644 index 0000000..b2e2330 --- /dev/null +++ b/usr.bin/ctags/ctags.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ctags.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include "ctags.h" + +/* + * ctags: create a tags file + */ + +NODE *head; /* head of the sorted binary tree */ + + /* boolean "func" (see init()) */ +bool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256]; + +FILE *inf; /* ioptr for current input file */ +FILE *outf; /* ioptr for tags file */ + +long lineftell; /* ftell after getc( inf ) == '\n' */ + +int lineno; /* line number of current line */ +int dflag; /* -d: non-macro defines */ +int tflag; /* -t: create tags for typedefs */ +int vflag; /* -v: vgrind style index output */ +int wflag; /* -w: suppress warnings */ +int xflag; /* -x: cxref style output */ + +char *curfile; /* current input file name */ +char searchar = '/'; /* use /.../ searches by default */ +char lbuf[LINE_MAX]; + +void init __P((void)); +void find_entries __P((char *)); + +int +main(argc, argv) + int argc; + char **argv; +{ + static char *outfile = "tags"; /* output file */ + int aflag; /* -a: append to tags */ + int uflag; /* -u: update tags */ + int exit_val; /* exit value */ + int step; /* step through args */ + int ch; /* getopts char */ + char cmd[100]; /* too ugly to explain */ + + aflag = uflag = NO; + while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != EOF) + switch(ch) { + case 'B': + searchar = '?'; + break; + case 'F': + searchar = '/'; + break; + case 'a': + aflag++; + break; + case 'd': + dflag++; + break; + case 'f': + outfile = optarg; + break; + case 't': + tflag++; + break; + case 'u': + uflag++; + break; + case 'w': + wflag++; + break; + case 'v': + vflag++; + case 'x': + xflag++; + break; + case '?': + default: + goto usage; + } + argv += optind; + argc -= optind; + if (!argc) { +usage: (void)fprintf(stderr, + "usage: ctags [-BFadtuwvx] [-f tagsfile] file ..."); + exit(1); + } + + init(); + + for (exit_val = step = 0; step < argc; ++step) + if (!(inf = fopen(argv[step], "r"))) { + warn("%s", argv[step]); + exit_val = 1; + } + else { + curfile = argv[step]; + find_entries(argv[step]); + (void)fclose(inf); + } + + if (head) + if (xflag) + put_entries(head); + else { + if (uflag) { + for (step = 0; step < argc; step++) { + (void)sprintf(cmd, + "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS", + outfile, argv[step], + outfile); + system(cmd); + } + ++aflag; + } + if (!(outf = fopen(outfile, aflag ? "a" : "w"))) + err(exit_val, "%s", outfile); + put_entries(head); + (void)fclose(outf); + if (uflag) { + (void)sprintf(cmd, "sort -o %s %s", + outfile, outfile); + system(cmd); + } + } + exit(exit_val); +} + +/* + * init -- + * this routine sets up the boolean psuedo-functions which work by + * setting boolean flags dependent upon the corresponding character. + * Every char which is NOT in that string is false with respect to + * the pseudo-function. Therefore, all of the array "_wht" is NO + * by default and then the elements subscripted by the chars in + * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in + * the string CWHITE, else NO. + */ +void +init() +{ + int i; + unsigned char *sp; + + for (i = 0; i < 256; i++) { + _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO; + _gd[i] = YES; + } +#define CWHITE " \f\t\n" + for (sp = CWHITE; *sp; sp++) /* white space chars */ + _wht[*sp] = YES; +#define CTOKEN " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?" + for (sp = CTOKEN; *sp; sp++) /* token ending chars */ + _etk[*sp] = YES; +#define CINTOK "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789" + for (sp = CINTOK; *sp; sp++) /* valid in-token chars */ + _itk[*sp] = YES; +#define CBEGIN "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + for (sp = CBEGIN; *sp; sp++) /* token starting chars */ + _btk[*sp] = YES; +#define CNOTGD ",;" + for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */ + _gd[*sp] = NO; +} + +/* + * find_entries -- + * this routine opens the specified file and calls the function + * which searches the file. + */ +void +find_entries(file) + char *file; +{ + char *cp; + + lineno = 0; /* should be 1 ?? KB */ + if (cp = strrchr(file, '.')) { + if (cp[1] == 'l' && !cp[2]) { + int c; + + for (;;) { + if (GETC(==, EOF)) + return; + if (!iswhite(c)) { + rewind(inf); + break; + } + } +#define LISPCHR ";([" +/* lisp */ if (strchr(LISPCHR, c)) { + l_entries(); + return; + } +/* lex */ else { + /* + * we search all 3 parts of a lex file + * for C references. This may be wrong. + */ + toss_yysec(); + (void)strcpy(lbuf, "%%$"); + pfnote("yylex", lineno); + rewind(inf); + } + } +/* yacc */ else if (cp[1] == 'y' && !cp[2]) { + /* + * we search only the 3rd part of a yacc file + * for C references. This may be wrong. + */ + toss_yysec(); + (void)strcpy(lbuf, "%%$"); + pfnote("yyparse", lineno); + y_entries(); + } +/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) { + if (PF_funcs()) + return; + rewind(inf); + } + } +/* C */ c_entries(); +} diff --git a/usr.bin/ctags/ctags.h b/usr.bin/ctags/ctags.h new file mode 100644 index 0000000..a42c68a --- /dev/null +++ b/usr.bin/ctags/ctags.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1987, 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. + * + * @(#)ctags.h 8.3 (Berkeley) 4/2/94 + */ + +#define bool char + +#define YES 1 +#define NO 0 +#define EOS '\0' + +#define ENDLINE 50 /* max length of pattern */ +#define MAXTOKEN 250 /* max size of single token */ + +#define SETLINE {++lineno;lineftell = ftell(inf);} +#define GETC(op,exp) ((c = getc(inf)) op (int)exp) + +#define iswhite(arg) (_wht[(unsigned)arg]) /* T if char is white */ +#define begtoken(arg) (_btk[(unsigned)arg]) /* T if char can start token */ +#define intoken(arg) (_itk[(unsigned)arg]) /* T if char can be in token */ +#define endtoken(arg) (_etk[(unsigned)arg]) /* T if char ends tokens */ +#define isgood(arg) (_gd[(unsigned)arg]) /* T if char can be after ')' */ + +typedef struct nd_st { /* sorting structure */ + struct nd_st *left, + *right; /* left and right sons */ + char *entry, /* function or type name */ + *file, /* file name */ + *pat; /* search pattern */ + int lno; /* for -x option */ + bool been_warned; /* set if noticed dup */ +} NODE; + +extern char *curfile; /* current input file name */ +extern NODE *head; /* head of the sorted binary tree */ +extern FILE *inf; /* ioptr for current input file */ +extern FILE *outf; /* ioptr for current output file */ +extern long lineftell; /* ftell after getc( inf ) == '\n' */ +extern int lineno; /* line number of current line */ +extern int dflag; /* -d: non-macro defines */ +extern int tflag; /* -t: create tags for typedefs */ +extern int vflag; /* -v: vgrind style index output */ +extern int wflag; /* -w: suppress warnings */ +extern int xflag; /* -x: cxref style output */ +extern bool _wht[], _etk[], _itk[], _btk[], _gd[]; +extern char lbuf[LINE_MAX]; +extern char *lbp; +extern char searchar; /* ex search character */ + +extern int cicmp __P((char *)); +extern void getline __P((void)); +extern void pfnote __P((char *, int)); +extern int skip_key __P((int)); +extern void put_entries __P((NODE *)); +extern void toss_yysec __P((void)); +extern void l_entries __P((void)); +extern void y_entries __P((void)); +extern int PF_funcs __P((void)); +extern void c_entries __P((void)); +extern void skip_comment __P((void)); diff --git a/usr.bin/ctags/fortran.c b/usr.bin/ctags/fortran.c new file mode 100644 index 0000000..d0db9ed --- /dev/null +++ b/usr.bin/ctags/fortran.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)fortran.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "ctags.h" + +static void takeprec __P((void)); + +char *lbp; /* line buffer pointer */ + +int +PF_funcs() +{ + bool pfcnt; /* pascal/fortran functions found */ + char *cp; + char tok[MAXTOKEN]; + + for (pfcnt = NO;;) { + lineftell = ftell(inf); + if (!fgets(lbuf, sizeof(lbuf), inf)) + return (pfcnt); + ++lineno; + lbp = lbuf; + if (*lbp == '%') /* Ratfor escape to fortran */ + ++lbp; + for (; isspace(*lbp); ++lbp) + continue; + if (!*lbp) + continue; + switch (*lbp | ' ') { /* convert to lower-case */ + case 'c': + if (cicmp("complex") || cicmp("character")) + takeprec(); + break; + case 'd': + if (cicmp("double")) { + for (; isspace(*lbp); ++lbp) + continue; + if (!*lbp) + continue; + if (cicmp("precision")) + break; + continue; + } + break; + case 'i': + if (cicmp("integer")) + takeprec(); + break; + case 'l': + if (cicmp("logical")) + takeprec(); + break; + case 'r': + if (cicmp("real")) + takeprec(); + break; + } + for (; isspace(*lbp); ++lbp) + continue; + if (!*lbp) + continue; + switch (*lbp | ' ') { + case 'f': + if (cicmp("function")) + break; + continue; + case 'p': + if (cicmp("program") || cicmp("procedure")) + break; + continue; + case 's': + if (cicmp("subroutine")) + break; + default: + continue; + } + for (; isspace(*lbp); ++lbp) + continue; + if (!*lbp) + continue; + for (cp = lbp + 1; *cp && intoken(*cp); ++cp) + continue; + if (cp = lbp + 1) + continue; + *cp = EOS; + (void)strcpy(tok, lbp); + getline(); /* process line for ex(1) */ + pfnote(tok, lineno); + pfcnt = YES; + } + /*NOTREACHED*/ +} + +/* + * cicmp -- + * do case-independent strcmp + */ +int +cicmp(cp) + char *cp; +{ + int len; + char *bp; + + for (len = 0, bp = lbp; *cp && (*cp &~ ' ') == (*bp++ &~ ' '); + ++cp, ++len) + continue; + if (!*cp) { + lbp += len; + return (YES); + } + return (NO); +} + +static void +takeprec() +{ + for (; isspace(*lbp); ++lbp) + continue; + if (*lbp == '*') { + for (++lbp; isspace(*lbp); ++lbp) + continue; + if (!isdigit(*lbp)) + --lbp; /* force failure */ + else + while (isdigit(*++lbp)) + continue; + } +} diff --git a/usr.bin/ctags/lisp.c b/usr.bin/ctags/lisp.c new file mode 100644 index 0000000..5f99984 --- /dev/null +++ b/usr.bin/ctags/lisp.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)lisp.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "ctags.h" + +/* + * lisp tag functions + * just look for (def or (DEF + */ +void +l_entries() +{ + int special; + char *cp; + char savedc; + char tok[MAXTOKEN]; + + for (;;) { + lineftell = ftell(inf); + if (!fgets(lbuf, sizeof(lbuf), inf)) + return; + ++lineno; + lbp = lbuf; + if (!cicmp("(def")) + continue; + special = NO; + switch(*lbp | ' ') { + case 'm': + if (cicmp("method")) + special = YES; + break; + case 'w': + if (cicmp("wrapper") || cicmp("whopper")) + special = YES; + } + for (; !isspace(*lbp); ++lbp) + continue; + for (; isspace(*lbp); ++lbp) + continue; + for (cp = lbp; *cp && *cp != '\n'; ++cp) + continue; + *cp = EOS; + if (special) { + if (!(cp = strchr(lbp, ')'))) + continue; + for (; cp >= lbp && *cp != ':'; --cp) + continue; + if (cp < lbp) + continue; + lbp = cp; + for (; *cp && *cp != ')' && *cp != ' '; ++cp) + continue; + } + else + for (cp = lbp + 1; + *cp && *cp != '(' && *cp != ' '; ++cp) + continue; + savedc = *cp; + *cp = EOS; + (void)strcpy(tok, lbp); + *cp = savedc; + getline(); + pfnote(tok, lineno); + } + /*NOTREACHED*/ +} diff --git a/usr.bin/ctags/print.c b/usr.bin/ctags/print.c new file mode 100644 index 0000000..b2c313a --- /dev/null +++ b/usr.bin/ctags/print.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)print.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include "ctags.h" + +/* + * getline -- + * get the line the token of interest occurred on, + * prepare it for printing. + */ +void +getline() +{ + long saveftell; + int c; + int cnt; + char *cp; + + saveftell = ftell(inf); + (void)fseek(inf, lineftell, L_SET); + if (xflag) + for (cp = lbuf; GETC(!=, '\n'); *cp++ = c) + continue; + /* + * do all processing here, so we don't step through the + * line more than once; means you don't call this routine + * unless you're sure you've got a keeper. + */ + else for (cnt = 0, cp = lbuf; GETC(!=, EOF) && cnt < ENDLINE; ++cnt) { + if (c == '\\') { /* backslashes */ + if (cnt > ENDLINE - 2) + break; + *cp++ = '\\'; *cp++ = '\\'; + ++cnt; + } + else if (c == (int)searchar) { /* search character */ + if (cnt > ENDLINE - 2) + break; + *cp++ = '\\'; *cp++ = c; + ++cnt; + } + else if (c == '\n') { /* end of keep */ + *cp++ = '$'; /* can find whole line */ + break; + } + else + *cp++ = c; + } + *cp = EOS; + (void)fseek(inf, saveftell, L_SET); +} + +/* + * put_entries -- + * write out the tags + */ +void +put_entries(node) + NODE *node; +{ + + if (node->left) + put_entries(node->left); + if (vflag) + printf("%s %s %d\n", + node->entry, node->file, (node->lno + 63) / 64); + else if (xflag) + printf("%-16s%4d %-16s %s\n", + node->entry, node->lno, node->file, node->pat); + else + fprintf(outf, "%s\t%s\t%c^%s%c\n", + node->entry, node->file, searchar, node->pat, searchar); + if (node->right) + put_entries(node->right); +} diff --git a/usr.bin/ctags/test/ctags.test b/usr.bin/ctags/test/ctags.test new file mode 100644 index 0000000..1f334ac --- /dev/null +++ b/usr.bin/ctags/test/ctags.test @@ -0,0 +1,67 @@ +int bar = (1 + 5); + +FOO("here is a #define test: ) {"); +char sysent[20]; +int nsysent = sizeof (sysent) / sizeof (sysent[0]); +/* + * now is the time for a comment. + * four lines in length... + */struct struct_xtra{int list;};r4(x,y){};typedef struct{int bar;}struct_xxe; +#define FOO BAR +struct struct_three { + int list; +}; +#define SINGLE +int BAD(); +enum color {red, green, gold, brown}; +char qq[] = " quote(one,two) {int bar;} "; +typedef struct { + int bar; + struct struct_two { + int foo; + union union_3 { + struct struct_three entry; + char size[25]; + }; + struct last { + struct struct_three xentry; + char list[34]; + }; + }; +} struct_one; +#define TWOLINE ((MAXLIST + FUTURE + 15) \ + / (time_to_live ? 3 : 4)) +#if (defined(BAR)) +int bar; +#endif +#define MULTIPLE {\ + multiple(one,two); \ + lineno++; \ + callroute(one,two); \ +} +#if defined(BAR) +int bar; +#endif +union union_one { + struct struct_three s3; + char foo[25]; +}; +#define XYZ(A,B) (A + B / 2) * (3 - 26 + l_lineno) +routine1(one,two) /* comments here are fun... */ + struct { + int entry; + char bar[34]; + } *one; + char two[10]; +{ +typedef unsigned char u_char; + register struct buf *bp; + five(one,two); +} + routine2 (one,two) { puts("hello\n"); } + routine3 +(one, +two) { puts("world\n"); } +routine4(int one, char (*two)(void)) /* test ANSI arguments */ +{ +} diff --git a/usr.bin/ctags/tree.c b/usr.bin/ctags/tree.c new file mode 100644 index 0000000..61decd2 --- /dev/null +++ b/usr.bin/ctags/tree.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)tree.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include "ctags.h" + +static void add_node __P((NODE *, NODE *)); +static void free_tree __P((NODE *)); + +/* + * pfnote -- + * enter a new node in the tree + */ +void +pfnote(name, ln) + char *name; + int ln; +{ + NODE *np; + char *fp; + char nbuf[MAXTOKEN]; + + /*NOSTRICT*/ + if (!(np = (NODE *)malloc(sizeof(NODE)))) { + warnx("too many entries to sort"); + put_entries(head); + free_tree(head); + /*NOSTRICT*/ + if (!(head = np = (NODE *)malloc(sizeof(NODE)))) + err(1, "out of space"); + } + if (!xflag && !strcmp(name, "main")) { + if (!(fp = strrchr(curfile, '/'))) + fp = curfile; + else + ++fp; + (void)sprintf(nbuf, "M%s", fp); + fp = strrchr(nbuf, '.'); + if (fp && !fp[2]) + *fp = EOS; + name = nbuf; + } + if (!(np->entry = strdup(name))) + err(1, NULL); + np->file = curfile; + np->lno = ln; + np->left = np->right = 0; + if (!(np->pat = strdup(lbuf))) + err(1, NULL); + if (!head) + head = np; + else + add_node(np, head); +} + +static void +add_node(node, cur_node) + NODE *node, + *cur_node; +{ + int dif; + + dif = strcmp(node->entry, cur_node->entry); + if (!dif) { + if (node->file == cur_node->file) { + if (!wflag) + fprintf(stderr, "Duplicate entry in file %s, line %d: %s\nSecond entry ignored\n", node->file, lineno, node->entry); + return; + } + if (!cur_node->been_warned) + if (!wflag) + fprintf(stderr, "Duplicate entry in files %s and %s: %s (Warning only)\n", node->file, cur_node->file, node->entry); + cur_node->been_warned = YES; + } + else if (dif < 0) + if (cur_node->left) + add_node(node, cur_node->left); + else + cur_node->left = node; + else if (cur_node->right) + add_node(node, cur_node->right); + else + cur_node->right = node; +} + +static void +free_tree(node) + NODE *node; +{ + while (node) { + if (node->right) + free_tree(node->right); + free(node); + node = node->left; + } +} diff --git a/usr.bin/ctags/yacc.c b/usr.bin/ctags/yacc.c new file mode 100644 index 0000000..c013283 --- /dev/null +++ b/usr.bin/ctags/yacc.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1987, 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[] = "@(#)yacc.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "ctags.h" + +/* + * y_entries: + * find the yacc tags and put them in. + */ +void +y_entries() +{ + int c; + char *sp; + bool in_rule; + char tok[MAXTOKEN]; + + in_rule = NO; + + while (GETC(!=, EOF)) + switch (c) { + case '\n': + SETLINE; + /* FALLTHROUGH */ + case ' ': + case '\f': + case '\r': + case '\t': + break; + case '{': + if (skip_key('}')) + in_rule = NO; + break; + case '\'': + case '"': + if (skip_key(c)) + in_rule = NO; + break; + case '%': + if (GETC(==, '%')) + return; + (void)ungetc(c, inf); + break; + case '/': + if (GETC(==, '*')) + skip_comment(); + else + (void)ungetc(c, inf); + break; + case '|': + case ';': + in_rule = NO; + break; + default: + if (in_rule || !isalpha(c) && c != '.' && c != '_') + break; + sp = tok; + *sp++ = c; + while (GETC(!=, EOF) && (intoken(c) || c == '.')) + *sp++ = c; + *sp = EOS; + getline(); /* may change before ':' */ + while (iswhite(c)) { + if (c == '\n') + SETLINE; + if (GETC(==, EOF)) + return; + } + if (c == ':') { + pfnote(tok, lineno); + in_rule = YES; + } + else + (void)ungetc(c, inf); + } +} + +/* + * toss_yysec -- + * throw away lines up to the next "\n%%\n" + */ +void +toss_yysec() +{ + int c; /* read character */ + int state; + + /* + * state == 0 : waiting + * state == 1 : received a newline + * state == 2 : received first % + * state == 3 : recieved second % + */ + lineftell = ftell(inf); + for (state = 0; GETC(!=, EOF);) + switch (c) { + case '\n': + ++lineno; + lineftell = ftell(inf); + if (state == 3) /* done! */ + return; + state = 1; /* start over */ + break; + case '%': + if (state) /* if 1 or 2 */ + ++state; /* goto 3 */ + break; + default: + state = 0; /* reset */ + break; + } +} diff --git a/usr.bin/cut/Makefile b/usr.bin/cut/Makefile new file mode 100644 index 0000000..19b0100 --- /dev/null +++ b/usr.bin/cut/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= cut + +.include diff --git a/usr.bin/cut/cut.1 b/usr.bin/cut/cut.1 new file mode 100644 index 0000000..97c5645 --- /dev/null +++ b/usr.bin/cut/cut.1 @@ -0,0 +1,110 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)cut.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt CUT 1 +.Os +.Sh NAME +.Nm cut +.Nd select portions of each line of a file +.Sh SYNOPSIS +.Nm cut +.Fl c Ar list +.Ar +.Nm cut +.Fl f Ar list +.Op Fl d Ar string +.Op Fl s +.Ar +.Sh DESCRIPTION +The +.Nm cut +utility selects portions of each line (as specified by +.Ar list ) +from each +.Ar file +(or the standard input by default), and writes them to the +standard output. +The items specified by +.Ar list +can be in terms of column position or in terms of fields delimited +by a special character. Column numbering starts from 1. +.Pp +.Ar List +is a comma or whitespace separated set of increasing numbers and/or +number ranges. +Number ranges consist of a number, a dash +.Pq Li \- , +and a second number +and select the fields or columns from the first number to the second, +inclusive. +Numbers or number ranges may be preceded by a dash, which selects all +fields or columns from 1 to the first number. +Numbers or number ranges may be followed by a dash, which selects all +fields or columns from the last number to the end of the line. +Numbers and number ranges may be repeated, overlapping, and in any order. +It is not an error to select fields or columns not present in the +input line. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl c Ar list +The +.Ar list +specifies character positions. +.It Fl d Ar string +Use the first character of +.Ar string +as the field delimiter character instead of the tab character. +.It Fl f Ar list +The +.Ar list +specifies fields, delimited in the input by a single tab character. +Output fields are separated by a single tab character. +.It Fl s +Suppresses lines with no field delimiter characters. +Unless specified, lines with no delimiters are passed through unmodified. +.El +.Pp +.Nm Cut +exits 0 on success, 1 if an error occurred. +.Sh SEE ALSO +.Xr paste 1 +.Sh STANDARDS +The +.Nm cut +utility is expected to conform to +.St -p1003.2 . diff --git a/usr.bin/cut/cut.c b/usr.bin/cut/cut.c new file mode 100644 index 0000000..25ffdd3 --- /dev/null +++ b/usr.bin/cut/cut.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)cut.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +int cflag; +char dchar; +int dflag; +int fflag; +int sflag; + +void c_cut __P((FILE *, char *)); +void err __P((const char *, ...)); +void f_cut __P((FILE *, char *)); +void get_list __P((char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + FILE *fp; + void (*fcn) __P((FILE *, char *)); + int ch; + + dchar = '\t'; /* default delimiter is \t */ + + while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF) + switch(ch) { + case 'c': + fcn = c_cut; + get_list(optarg); + cflag = 1; + break; + case 'd': + dchar = *optarg; + dflag = 1; + break; + case 'f': + get_list(optarg); + fcn = f_cut; + fflag = 1; + break; + case 's': + sflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (fflag) { + if (cflag) + usage(); + } else if (!cflag || dflag || sflag) + usage(); + + if (*argv) + for (; *argv; ++argv) { + if (!(fp = fopen(*argv, "r"))) + err("%s: %s\n", *argv, strerror(errno)); + fcn(fp, *argv); + (void)fclose(fp); + } + else + fcn(stdin, "stdin"); + exit(0); +} + +int autostart, autostop, maxval; + +char positions[_POSIX2_LINE_MAX + 1]; + +void +get_list(list) + char *list; +{ + register int setautostart, start, stop; + register char *pos; + char *p; + + /* + * set a byte in the positions array to indicate if a field or + * column is to be selected; use +1, it's 1-based, not 0-based. + * This parser is less restrictive than the Draft 9 POSIX spec. + * POSIX doesn't allow lists that aren't in increasing order or + * overlapping lists. We also handle "-3-5" although there's no + * real reason too. + */ + for (; p = strtok(list, ", \t"); list = NULL) { + setautostart = start = stop = 0; + if (*p == '-') { + ++p; + setautostart = 1; + } + if (isdigit(*p)) { + start = stop = strtol(p, &p, 10); + if (setautostart && start > autostart) + autostart = start; + } + if (*p == '-') { + if (isdigit(p[1])) + stop = strtol(p + 1, &p, 10); + if (*p == '-') { + ++p; + if (!autostop || autostop > stop) + autostop = stop; + } + } + if (*p) + err("[-cf] list: illegal list value\n"); + if (!stop || !start) + err("[-cf] list: values may not include zero\n"); + if (stop > _POSIX2_LINE_MAX) + err("[-cf] list: %d too large (max %d)\n", + stop, _POSIX2_LINE_MAX); + if (maxval < stop) + maxval = stop; + for (pos = positions + start; start++ <= stop; *pos++ = 1); + } + + /* overlapping ranges */ + if (autostop && maxval > autostop) + maxval = autostop; + + /* set autostart */ + if (autostart) + memset(positions + 1, '1', autostart); +} + +/* ARGSUSED */ +void +c_cut(fp, fname) + FILE *fp; + char *fname; +{ + register int ch, col; + register char *pos; + + for (;;) { + pos = positions + 1; + for (col = maxval; col; --col) { + if ((ch = getc(fp)) == EOF) + return; + if (ch == '\n') + break; + if (*pos++) + (void)putchar(ch); + } + if (ch != '\n') + if (autostop) + while ((ch = getc(fp)) != EOF && ch != '\n') + (void)putchar(ch); + else + while ((ch = getc(fp)) != EOF && ch != '\n'); + (void)putchar('\n'); + } +} + +void +f_cut(fp, fname) + FILE *fp; + char *fname; +{ + register int ch, field, isdelim; + register char *pos, *p, sep; + int output; + char lbuf[_POSIX2_LINE_MAX + 1]; + + for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) { + for (isdelim = 0, p = lbuf;; ++p) { + if (!(ch = *p)) + err("%s: line too long.\n", fname); + /* this should work if newline is delimiter */ + if (ch == sep) + isdelim = 1; + if (ch == '\n') { + if (!isdelim && !sflag) + (void)printf("%s", lbuf); + break; + } + } + if (!isdelim) + continue; + + pos = positions + 1; + for (field = maxval, p = lbuf; field; --field, ++pos) { + if (*pos) { + if (output++) + (void)putchar(sep); + while ((ch = *p++) != '\n' && ch != sep) + (void)putchar(ch); + } else + while ((ch = *p++) != '\n' && ch != sep); + if (ch == '\n') + break; + } + if (ch != '\n') + if (autostop) { + if (output) + (void)putchar(sep); + for (; (ch = *p) != '\n'; ++p) + (void)putchar(ch); + } else + for (; (ch = *p) != '\n'; ++p); + (void)putchar('\n'); + } +} + +void +usage() +{ + (void)fprintf(stderr, +"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "cut: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/diff/diff/diff.1 b/usr.bin/diff/diff/diff.1 new file mode 100644 index 0000000..1b5c078 --- /dev/null +++ b/usr.bin/diff/diff/diff.1 @@ -0,0 +1,387 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)diff.1 8.1 (Berkeley) 6/30/93 +.\" +.Dd June 30, 1993 +.Dt DIFF 1 +.Os BSD 4 +.Sh NAME +.Nm diff +.Nd differential file and directory comparator +.Sh SYNOPSIS +.Nm diff +.Op Fl cefhn +.Op Fl biwt +.Ar file1 file2 +.Nm diff +.Op Fl D Ns Ar string +.Op Fl biw +.Ar file1 file2 +.Nm diff +.Op Fl l +.Op Fl r +.Op Fl s +.Op Fl cefhn +.Op Fl biwt +.Op Fl S Ns Ar name +.Ar dir1 dir2 +.Sh DESCRIPTION +The +.Nm diff +utility compares the contents of +.Ar file1 +and +.Ar file2 +and writes to the standard output the list of changes necessary to +convert one file into the other. +No output is produced if the files are identical. +.Pp +Output options (mutually exclusive): +.Bl -tag -width Ds +.It Fl c +produces a diff with lines of context. +The default is to present 3 lines of context and may be changed, e.g., to 10, by +.Fl c10 . +With +.Fl c +the output format is modified slightly: +the output beginning with identification of the files involved and +their creation dates and then each change is separated +by a line with a dozen *'s. +The lines removed from +.Ar file1 +are marked with `\(mi '; those added to +.Ar file2 +are marked `+ '. Lines which are changed from one +file to the other are marked in both files with `! '. +Changes which lie within lines of each other are grouped +together on output. (This is a change from the previous ``diff -c'' +but the resulting output is usually much easier to interpret.) +.It Fl e +produces output in a form suitable as input for the editor utility, +.Xr ed 1 , +which can then be used to convert file1 into file2. +.Pp +Extra commands are added to the output when comparing directories with +.Fl e , +so that the result is a +.Xr sh 1 +script for converting text files which are common to the two directories +from their state in +.Ar dir1 +to their state in +.Ar dir2 . +.It Fl f +identical output to that of the +.Fl e +flag, but in reverse order. It cannot +be digested by +.Xr ed 1 . +.It Fl h +Invokes an alternate algorithm which can handle files of very long lengths. +There is a trade off. The algorithm can only deal with changes which are +clearly delimited and brief. Long sections of changes and overlaps will +confuse it. +.It Fl n +produces a script similar to that of +.Fl e , +but in the opposite order and with a count of changed lines on each +insert or delete command. This is the form used by +.Xr rcsdiff 1 . +.It Fl D Ns Ar string +creates a merged version of +.Ar file1 +and +.Ar file2 +on the standard output, with C preprocessor controls included so that +a compilation of the result without defining +.Ar string +is equivalent +to compiling +.Ar file1 , +while defining +.Ar string +will yield +.Ar file2 . +.El +.Pp +Comparison options: +.Bl -tag -width Ds +.It Fl b +causes trailing blanks (spaces and tabs) to be ignored, and other +strings of blanks to compare equal. +.It Fl i +ignores the case of letters. E.g., ``A'' will compare equal to ``a''. +.It Fl t +will expand tabs in output lines. Normal or +.Fl c +output adds character(s) to the front of each line which may screw up +the indentation of the original source lines and make the output listing +difficult to interpret. This option will preserve the original source's +indentation. +.It Fl w +is similar to +.Fl b +but causes whitespace (blanks and tabs) to be totally ignored. E.g., +``if\ (\ a\ ==\ b\ )'' will compare equal to ``if(a==b)''. +.El +.Pp +Directory comparison options: +.Bl -tag -width Ds +.It Fl l +long output format; each text file +.Nm diff Ns \'d +is piped through +.Xr pr 1 +to paginate it, +other differences are remembered and summarized +after all text file differences are reported. +.It Fl r +causes application of +.Nm diff +recursively to common subdirectories encountered. +.It Fl s +causes +.Nm diff +to report files which are the same, which are otherwise not mentioned. +.It Fl S Ns Ar name +re-starts a directory +.Nm diff +in the middle beginning with file +.Ar name . +.El +.Pp +If both arguments are directories, +.Nm diff +sorts the contents of the directories by name, and then runs the +regular file +.Nm diff +algorithm, producing a change list, +on text files which are different. +Binary files which differ, +common subdirectories, and files which appear in only one directory +are described as such. +.Pp +If only one of +.Ar file1 +and +.Ar file2 +is a directory, +.Nm diff +is applied to the non-directory file and the file contained in +the directory file with a filename that is the same as the +last component of the non-directory file. +.Pp +If either +.Ar file1 +or +.Ar file2 +is +.Sq Fl , +the standard input is +used in its place. +.Ss Output Style +The default (without +.Fl e , +.Fl c , +or +.Fl n +.\" -C +options) +output contains lines of these forms, where +.Va XX , YY , ZZ , QQ +are line numbers respective of file order. +.Pp +.Bl -tag -width "XX,YYcZZ,QQ" -compact +.It Li XX Ns Ic a Ns Li YY +At (the end of) line +.Va XX +of +.Ar file1 , +append the contents +of line +.Va YY +of +.Ar file2 +to make them equal. +.It Li XX Ns Ic a Ns Li YY,ZZ +Same as above, but append the range of lines, +.Va YY +through +.Va ZZ +of +.Ar file2 +to line +.Va XX +of file1. +.It Li XX Ns Ic d Ns Li YY +At line +.Va XX +delete +the line. The value +.Va YY +tells to which line the change +would bring +.Ar file1 +in line with +.Ar file1 . +.It Li XX,YY Ns Ic d Ns Li ZZ +Delete the range of lines +.Va XX +through +.Va YY +in +.Ar file1 . +.It Li XX Ns Ic c Ns Li YY +Change the line +.Va XX +in +.Ar file1 +to the line +.Va YY +in +.Ar file2. +.It Li XX,YY Ns Ic c Ns Li ZZ +Replace the range of specified lines with the line +.Va ZZ . +.It Li XX,YY Ns Ic c Ns Li ZZ,QQ +Replace the range +.Va XX , Ns YY +from +.Ar file1 +with the range +.Va ZZ , Ns QQ +from +.Ar file2 . +.El +.Pp +These lines resemble +.Xr ed 1 +subcommands to convert +.Ar file1 +into +.Ar file2 . +The line numbers before the action letters pertain to +.Ar file1 ; +those after pertain to +.Ar file2 . +Thus, by exchanging +.Ic a +for +.Ic d +and reading the line in reverse order, one can also +determine how to convert +.Ar file2 +into +.Ar file1 . +As in +.Xr ed 1 , +identical +pairs (where num1 = num2) are abbreviated as a single +number. +.Sh ENVIRONMENT +.Bl -tag -width TMPDIR +.It Ev TMPDIR +If the environment variable +.Ev TMPDIR +exists, +.Nm diff +will use the directory specified by +.Ev TMPDIR +as the temporary directory. +.El +.Sh FILES +.Bl -tag -width /usr/bin/diffh -compact +.It Pa /tmp/d????? +.It Pa /usr/bin/diffh +Alternate algorithm version (used by option +.Fl h ) . +.It Pa /usr/bin/diff +for directory diffs +.It Pa /usr/bin/pr +used by the +.Fl l +option. +.El +.Sh SEE ALSO +.Xr cmp 1 , +.Xr cc 1 , +.Xr comm 1 , +.Xr ed 1 , +.Xr diff3 1 +.br +.ne 1i +.Sh DIAGNOSTICS +The +.Nm diff +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It \&0 +No differences were found. +.It \&1 +Differences were found. +.It "\&>\&1" +An error occurred. +.El +.Sh BUGS +The +.Fl f +and +.Fl e +options +do not provide special handling for lines on which the +first and only character is +.Dq Li \&. . +This can cause problems for +.Xr ed 1 . +.Pp +When comparing directories with the +.Fl b , +.Fl w +or +.Fl i +options specified, +.Nm diff +first compares the files ala +.Ar cmp , +and then decides to run the +.Nm diff +algorithm if they are not equal. +This may cause a small amount of spurious output if the files +then turn out to be identical because the only differences are +insignificant white space or case differences. +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/diff/diff3/diff3.1 b/usr.bin/diff/diff3/diff3.1 new file mode 100644 index 0000000..09b1d72 --- /dev/null +++ b/usr.bin/diff/diff3/diff3.1 @@ -0,0 +1,172 @@ +.\" Copyright (c) 1990, 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. +.\" +.\" @(#)diff3.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt DIFF3 1 +.Os BSD 4.3R +.Sh NAME +.Nm diff3 +.Nd 3-way differential file comparison +.Sh SYNOPSIS +.Nm diff3 +.Op Fl exEX3 +.Ar file1 file2 file3 +.Sh DESCRIPTION +The +.Nm diff3 +utility compares the contents of three different versions of a file, +.Ar file1 , +.Ar file2 +and +.Ar file3 , +writing the result to the standard output. +The options describe different methods of merging and +purging +the separate versions into a new file. +.Nm Diff3 +is used by +.Xr RCS 1 +to merge specific versions or create +new versions. +.Pp +Options are: +.Bl -tag -width "--E, --X" +.It Fl e +Produces output in a form suitable as an input script for the +.Xr ed 1 +utility. The script may then be used to merge differences common +between all three files and differences specific to file1 and file3. +In other words, the +.Fl e +option ignores differences specific to file1 and file2, and those +specific to file2 and file3. It is useful for backing out changes +specific to file2 only. +.It Fl x +Produces an output script suitable for +.Xr ed 1 +with changes +specific only to all three versions. +.It Fl 3 +Produces an output script suitable for +.Xr ed 1 +with changes +specific only to file3. +.It Fl E , X +Similar to +.Fl e +and +.Fl x , +respectively, but treat overlapping changes (i.e., changes that would +be noted with ==== in the normal listing) differently. The overlapping +lines from both files will be inserted by the edit script, bracketed +by "<<<<<<" and ">>>>>>" lines. +.El +.Pp +The +.Fl E +option is used by +.Tn RCS +.Xr merge 1 +to insure that overlapping changes in the merged files are preserved +and brought to someone's attention. +.Pp +For example, suppose lines 7-8 are changed in both file1 and file2. +Applying the edit script generated by the command +.Pp +.Dl diff3 -E file1 file2 file3 +.Pp +to file1 results in the file: +.Pp +.Bd -literal -offset indent -compact +lines 1-6 +of file1 +<<<<<<< file1 +lines 7-8 +of file1 +======= +lines 7-8 +of file3 +>>>>>>> file3 +rest of file1 +.Ed +.Pp +The default output of +.Nm diff3 +makes notation of the differences between all files, and those differences +specific to each pair of files. The +changes are described by +the commands necessary for +.Xr ed 1 +to create the desired target from the different versions. +See +.Xr diff 1 +for a description of the commands. +.Bl -tag -width "=====" +.It Li \&==== +The lines beneath this notation are ranges of lines which are different +between all files. +.It \&==== Ns Va n +The lines beneath this notation are ranges of lines which are exclusively +different in file +.Va n . +.El +.Sh FILES +.Bl -tag -width /usr/bin/diff3 -compact +.It Pa /tmp/d3????? +temporary files. +.It Pa /usr/bin/diff3 +the executable. +.El +.Sh SEE ALSO +.Xr diff 1 +.Xr ed 1 +.Xr rcs 1 +.Sh BUGS +The +.Fl e +option +cannot catch and change +lines which have +.Ql \&. +as the first and only character on the line. +The resulting script will fail on that line +as +.Ql \&. +is an +.Xr ed 1 +editing command. +.Sh HISTORY +A +.Nm +command appeared in +.At v7 . diff --git a/usr.bin/dirname/Makefile b/usr.bin/dirname/Makefile new file mode 100644 index 0000000..76b4089 --- /dev/null +++ b/usr.bin/dirname/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= dirname +NOMAN= noman + +.include diff --git a/usr.bin/dirname/dirname.c b/usr.bin/dirname/dirname.c new file mode 100644 index 0000000..9586e5b --- /dev/null +++ b/usr.bin/dirname/dirname.c @@ -0,0 +1,144 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)dirname.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *p; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + /* + * (1) If string is //, skip steps (2) through (5). + * (2) If string consists entirely of slash characters, string + * shall be set to a single slash character. In this case, + * skip steps (3) through (8). + */ + for (p = *argv;; ++p) { + if (!*p) { + if (p > *argv) + (void)printf("/\n"); + else + (void)printf(".\n"); + exit(0); + } + if (*p != '/') + break; + } + + /* + * (3) If there are any trailing slash characters in string, they + * shall be removed. + */ + for (; *p; ++p); + while (*--p == '/') + continue; + *++p = '\0'; + + /* + * (4) If there are no slash characters remaining in string, + * string shall be set to a single period character. In this + * case skip steps (5) through (8). + * + * (5) If there are any trailing nonslash characters in string, + * they shall be removed. + */ + while (--p >= *argv) + if (*p == '/') + break; + ++p; + if (p == *argv) { + (void)printf(".\n"); + exit(0); + } + + /* + * (6) If the remaining string is //, it is implementation defined + * whether steps (7) and (8) are skipped or processed. + * + * This case has already been handled, as part of steps (1) and (2). + */ + + /* + * (7) If there are any trailing slash characters in string, they + * shall be removed. + */ + while (--p >= *argv) + if (*p != '/') + break; + ++p; + + /* + * (8) If the remaining string is empty, string shall be set to + * a single slash character. + */ + *p = '\0'; + (void)printf("%s\n", p == *argv ? "/" : *argv); + exit(0); +} + +void +usage() +{ + + (void)fprintf(stderr, "usage: dirname path\n"); + exit(1); +} diff --git a/usr.bin/du/Makefile b/usr.bin/du/Makefile new file mode 100644 index 0000000..3b5f135 --- /dev/null +++ b/usr.bin/du/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= du + +.include diff --git a/usr.bin/du/du.1 b/usr.bin/du/du.1 new file mode 100644 index 0000000..4ecce8e --- /dev/null +++ b/usr.bin/du/du.1 @@ -0,0 +1,117 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)du.1 8.2 (Berkeley) 4/1/94 +.\" +.Dd April 1, 1994 +.Dt DU 1 +.Os +.Sh NAME +.Nm du +.Nd display disk usage statistics +.Sh SYNOPSIS +.Nm du +.Op Fl H | Fl L | Fl P +.Op Fl a | Fl s +.Op Fl x +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm du +utility displays the file system block usage for each file argument +and for each directory in the file hierarchy rooted in each directory +argument. +If no file is specified, the block usage of the hierarchy rooted in +the current directory is displayed. +The number of blocks are in the same units as that returned by the +.Xr stat 2 +system call, i.e. 512-byte blocks. +Partial numbers of blocks are rounded up. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl H +Symbolic links on the command line are followed. +(Symbolic links encountered in the tree traversal are not followed.) +.It Fl L +All symbolic links are followed. +.It Fl P +No symbolic links are followed. +.It Fl a +Display an entry for each file in the file hierarchy. +.It Fl s +Display only the grand total for the specified files. +.It Fl x +Filesystem mount points are not traversed. +.El +.Pp +.Nm Du +counts the storage used by symbolic links and not the files they +reference unless the +.Fl H +or +.Fl L +option is specified. +If either the +.Fl H +or +.Fl L +options are specified, storage used by any symbolic links which are +followed is not counted or displayed. +The +.Fl H , +.Fl L +and +.Fl P +options override each other and the command's actions are determined +by the last one specified. +.Pp +Files having multiple hard links are counted (and displayed) a single +time per +.Nm du +execution. +.Sh ENVIRONMENTAL VARIABLES +.Bl -tag -width BLOCKSIZE +.It Ev BLOCKSIZE +If the environmental variable +.Ev BLOCKSIZE +is set, the block counts will be displayed in units of that size block. +.El +.Sh SEE ALSO +.Xr df 1 , +.Xr fts 3 , +.Xr symlink 7 , +.Xr quot 8 +.Sh HISTORY +A +.Nm du +command appeared in +.At v6 . diff --git a/usr.bin/du/du.c b/usr.bin/du/du.c new file mode 100644 index 0000000..48869de --- /dev/null +++ b/usr.bin/du/du.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Newcomb. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)du.c 8.4 (Berkeley) 4/1/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +int linkchk __P((FTSENT *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + FTS *fts; + FTSENT *p; + long blocksize; + int ftsoptions, listdirs, listfiles; + int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag; + char **save; + + save = argv; + Hflag = Lflag = Pflag = aflag = sflag = 0; + ftsoptions = FTS_PHYSICAL; + while ((ch = getopt(argc, argv, "HLPasx")) != EOF) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'a': + aflag = 1; + break; + case 's': + sflag = 1; + break; + case 'x': + ftsoptions |= FTS_XDEV; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* + * XXX + * Because of the way that fts(3) works, logical walks will not count + * the blocks actually used by symbolic links. We rationalize this by + * noting that users computing logical sizes are likely to do logical + * copies, so not counting the links is correct. The real reason is + * that we'd have to re-implement the kernel's symbolic link traversing + * algorithm to get this right. If, for example, you have relative + * symbolic links referencing other relative symbolic links, it gets + * very nasty, very fast. The bottom line is that it's documented in + * the man page, so it's a feature. + */ + if (Hflag) + ftsoptions |= FTS_COMFOLLOW; + if (Lflag) { + ftsoptions &= ~FTS_PHYSICAL; + ftsoptions |= FTS_LOGICAL; + } + + if (aflag) { + if (sflag) + usage(); + listdirs = listfiles = 1; + } else if (sflag) + listdirs = listfiles = 0; + else { + listfiles = 0; + listdirs = 1; + } + + if (!*argv) { + argv = save; + argv[0] = "."; + argv[1] = NULL; + } + + (void)getbsize(¬used, &blocksize); + blocksize /= 512; + + if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) + err(1, NULL); + + for (rval = 0; (p = fts_read(fts)) != NULL;) + switch (p->fts_info) { + case FTS_D: /* Ignore. */ + break; + case FTS_DP: + p->fts_parent->fts_number += + p->fts_number += p->fts_statp->st_blocks; + /* + * If listing each directory, or not listing files + * or directories and this is post-order of the + * root of a traversal, display the total. + */ + if (listdirs || !listfiles && !p->fts_level) + (void)printf("%ld\t%s\n", + howmany(p->fts_number, blocksize), + p->fts_path); + break; + case FTS_DC: /* Ignore. */ + break; + case FTS_DNR: /* Warn, continue. */ + case FTS_ERR: + case FTS_NS: + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + break; + default: + if (p->fts_statp->st_nlink > 1 && linkchk(p)) + break; + /* + * If listing each file, or a non-directory file was + * the root of a traversal, display the total. + */ + if (listfiles || !p->fts_level) + (void)printf("%qd\t%s\n", + howmany(p->fts_statp->st_blocks, blocksize), + p->fts_path); + p->fts_parent->fts_number += p->fts_statp->st_blocks; + } + if (errno) + err(1, "fts_read"); + exit(0); +} + +typedef struct _ID { + dev_t dev; + ino_t inode; +} ID; + +int +linkchk(p) + FTSENT *p; +{ + static ID *files; + static int maxfiles, nfiles; + ID *fp, *start; + ino_t ino; + dev_t dev; + + ino = p->fts_statp->st_ino; + dev = p->fts_statp->st_dev; + if ((start = files) != NULL) + for (fp = start + nfiles - 1; fp >= start; --fp) + if (ino == fp->inode && dev == fp->dev) + return (1); + + if (nfiles == maxfiles && (files = realloc((char *)files, + (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) + err(1, ""); + files[nfiles].inode = ino; + files[nfiles].dev = dev; + ++nfiles; + return (0); +} + +void +usage() +{ + + (void)fprintf(stderr, + "usage: du [-H | -L | -P] [-a | -s] [-x] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/env/Makefile b/usr.bin/env/Makefile new file mode 100644 index 0000000..6b67b73 --- /dev/null +++ b/usr.bin/env/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= env +NOMAN= noman + +.include diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c new file mode 100644 index 0000000..2c72ddb --- /dev/null +++ b/usr.bin/env/env.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +extern char **environ; + +int +main(argc, argv) + int argc; + char **argv; +{ + char **ep, *p; + char *cleanenv[1]; + int ch; + + while ((ch = getopt(argc, argv, "-")) != EOF) + switch(ch) { + case '-': + environ = cleanenv; + cleanenv[0] = NULL; + break; + case '?': + default: + (void)fprintf(stderr, + "usage: env [-] [name=value ...] [command]\n"); + exit(1); + } + for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) + (void)setenv(*argv, ++p, 1); + if (*argv) { + execvp(*argv, argv); + err(1, "%s", *argv); + } + for (ep = environ; *ep; ep++) + (void)printf("%s\n", *ep); + exit(0); +} diff --git a/usr.bin/error/Makefile b/usr.bin/error/Makefile new file mode 100644 index 0000000..4ec0ba0 --- /dev/null +++ b/usr.bin/error/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= error +SRCS= main.c input.c pi.c subr.c filter.c touch.c + +.include diff --git a/usr.bin/error/error.1 b/usr.bin/error/error.1 new file mode 100644 index 0000000..ad7adf8 --- /dev/null +++ b/usr.bin/error/error.1 @@ -0,0 +1,304 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)error.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt ERROR 1 +.Os BSD 4 +.Sh NAME +.Nm error +.Nd analyze and disperse compiler error messages +.Sh SYNOPSIS +.Nm error +.Op Fl n +.Op Fl s +.Op Fl q +.Op Fl v +.Op Fl t Ar suffixlist +.Op Fl I Ar ignorefile +.Op name +.Sh DESCRIPTION +.Nm Error +analyzes and optionally disperses the diagnostic error messages +produced by a number of compilers and language processors to the source +file and line where the errors occurred. It can replace the painful, +traditional methods of scribbling abbreviations of errors on paper, and +permits error messages and source code to be viewed simultaneously +without machinations of multiple windows in a screen editor. +.Pp +Options are: +.Bl -tag -width Ds +.It Fl n +Do +.Em not +touch any files; all error messages are sent to the +standard output. +.It Fl q +The user is +.Ar queried +whether s/he wants to touch the file. +A ``y'' or ``n'' to the question is necessary to continue. +Absence of the +.Fl q +option implies that all referenced files +(except those referring to discarded error messages) +are to be touched. +.It Fl v +After all files have been touched, +overlay the visual editor +.Xr \&vi 1 +with it set up to edit all files touched, +and positioned in the first touched file at the first error. +If +.Xr \&vi 1 +can't be found, try +.Xr \&ex 1 +or +.Xr \&ed 1 +from standard places. +.It Fl t +Take the following argument as a suffix list. +Files whose suffixes do not appear in the suffix list are not touched. +The suffix list is dot separated, and ``*'' wildcards work. +Thus the suffix list: +.Pp +.Dl ".c.y.foo*.h" +.Pp +allows +.Nm error +to touch files ending with ``.c'', ``.y'', ``.foo*'' and ``.y''. +.It Fl s +Print out +.Em statistics +regarding the error categorization. +Not too useful. +.El +.Pp +.Nm Error +looks at the error messages, +either from the specified file +.Ar name +or from the standard input, +and attempts to determine which +language processor produced each error message, +determines the source file and line number to which the error message refers, +determines if the error message is to be ignored or not, +and inserts the (possibly slightly modified) error message into +the source file as a comment on the line preceding to which the +line the error message refers. +Error messages which can't be categorized by language processor +or content are not inserted into any file, +but are sent to the standard output. +.Nm Error +touches source files only after all input has been read. +.Pp +.Nm Error +is intended to be run +with its standard input +connected via a pipe to the error message source. +Some language processors put error messages on their standard error file; +others put their messages on the standard output. +Hence, both error sources should be piped together into +.Nm error . +For example, when using the +.Xr csh 1 +syntax, +.Pp +.Dl make \-s lint \&| error \-q \-v +.Pp +will analyze all the error messages produced +by whatever programs +.Xr make 1 +runs when making lint. +.Pp +.Nm Error +knows about the error messages produced by: +.Xr make 1 , +.Xr \&cc 1 , +.Xr cpp 1 , +.Xr ccom 1 , +.Xr \&as 1 , +.Xr \&ld 1 , +.Xr lint 1 , +.Xr \&pi 1 , +.Xr \&pc 1 , +.Xr f77 1 , +and +.Em DEC Western Research Modula\-2 . +.Nm Error +knows a standard format for error messages produced by +the language processors, +so is sensitive to changes in these formats. +For all languages except +.Em Pascal , +error messages are restricted to be on one line. +Some error messages refer to more than one line in more than +one files; +.Nm error +will duplicate the error message and insert it at +all of the places referenced. +.Pp +.Nm Error +will do one of six things with error messages. +.Bl -tag -width Em synchronize +.It Em synchronize +Some language processors produce short errors describing +which file it is processing. +.Nm Error +uses these to determine the file name for languages that +don't include the file name in each error message. +These synchronization messages are consumed entirely by +.Nm error . +.It Em discard +Error messages from +.Xr lint 1 +that refer to one of the two +.Xr lint 1 +libraries, +.Pa /usr/libdata/lint/llib-lc +and +.Pa /usr/libdata/lint/llib-port +are discarded, +to prevent accidently touching these libraries. +Again, these error messages are consumed entirely by +.Nm error . +.It Em nullify +Error messages from +.Xr lint 1 +can be nullified if they refer to a specific function, +which is known to generate diagnostics which are not interesting. +Nullified error messages are not inserted into the source file, +but are written to the standard output. +The names of functions to ignore are taken from +either the file named +.Pa .errorrc +in the users's home directory, +or from the file named by the +.Fl I +option. +If the file does not exist, +no error messages are nullified. +If the file does exist, there must be one function +name per line. +.It Em not file specific +Error messages that can't be intuited are grouped together, +and written to the standard output before any files are touched. +They will not be inserted into any source file. +.It Em file specific +Error message that refer to a specific file, +but to no specific line, +are written to the standard output when +that file is touched. +.It Em true errors +Error messages that can be intuited are candidates for +insertion into the file to which they refer. +.El +.Pp +Only true error messages are candidates for inserting into +the file they refer to. +Other error messages are consumed entirely by +.Nm error +or are written to the standard output. +.Nm Error +inserts the error messages into the source file on the line +preceding the line the language processor found in error. +Each error message is turned into a one line comment for the +language, +and is internally flagged +with the string ``###'' at +the beginning of the error, +and ``%%%'' at the end of the error. +This makes pattern searching for errors easier with an editor, +and allows the messages to be easily removed. +In addition, each error message contains the source line number +for the line the message refers to. +A reasonably formatted source program can be recompiled +with the error messages still in it, +without having the error messages themselves cause future errors. +For poorly formatted source programs in free format languages, +such as C or Pascal, +it is possible to insert a comment into another comment, +which can wreak havoc with a future compilation. +To avoid this, programs with comments and source +on the same line should be formatted +so that language statements appear before comments. +.Pp +.Nm Error +catches interrupt and terminate signals, +and if in the insertion phase, +will orderly terminate what it is doing. +.Sh FILES +.Bl -tag -width ~/.errorrc -compact +.It Pa ~/.errorrc +function names to ignore for +.Xr lint 1 +error messages +.It Pa /dev/tty +user's teletype +.El +.Sh HISTORY +The +.Nm error +command +appeared in +.Bx 4.0 . +.Sh AUTHOR +Robert Henry +.Sh BUGS +.Pp +Opens the teletype directly to do user querying. +.Pp +Source files with links make a new copy of the file with +only one link to it. +.Pp +Changing a language processor's format of error messages +may cause +.Nm error +to not understand the error message. +.Pp +.Nm Error , +since it is purely mechanical, +will not filter out subsequent errors caused by `floodgating' +initiated by one syntactically trivial error. +Humans are still much better at discarding these related errors. +.Pp +Pascal error messages belong after the lines affected +(error puts them before). The alignment of the `\\' marking +the point of error is also disturbed by +.Nm error . +.Pp +.Nm Error +was designed for work on +.Tn CRT Ns 's +at reasonably high speed. +It is less pleasant on slow speed terminals, and has never been +used on hardcopy terminals. diff --git a/usr.bin/error/error.h b/usr.bin/error/error.h new file mode 100644 index 0000000..7ceb2a2 --- /dev/null +++ b/usr.bin/error/error.h @@ -0,0 +1,224 @@ +/* + * 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. + * + * @(#)error.h 8.1 (Berkeley) 6/6/93 + */ + +typedef int boolean; +#define reg register + +#define TRUE 1 +#define FALSE 0 + +#define true 1 +#define false 0 +/* + * Descriptors for the various languages we know about. + * If you touch these, also touch lang_table + */ +#define INUNKNOWN 0 +#define INCPP 1 +#define INCC 2 +#define INAS 3 +#define INLD 4 +#define INLINT 5 +#define INF77 6 +#define INPI 7 +#define INPC 8 +#define INFRANZ 9 +#define INLISP 10 +#define INVAXIMA 11 +#define INRATFOR 12 +#define INLEX 13 +#define INYACC 14 +#define INAPL 15 +#define INMAKE 16 +#define INRI 17 +#define INTROFF 18 +#define INMOD2 19 + +extern int language; +/* + * We analyze each line in the error message file, and + * attempt to categorize it by type, as well as language. + * Here are the type descriptors. + */ +typedef int Errorclass; + +#define C_FIRST 0 /* first error category */ +#define C_UNKNOWN 0 /* must be zero */ +#define C_IGNORE 1 /* ignore the message; used for pi */ +#define C_SYNC 2 /* synchronization errors */ +#define C_DISCARD 3 /* touches dangerous files, so discard */ +#define C_NONSPEC 4 /* not specific to any file */ +#define C_THISFILE 5 /* specific to this file, but at no line */ +#define C_NULLED 6 /* refers to special func; so null */ +#define C_TRUE 7 /* fits into true error format */ +#define C_DUPL 8 /* sub class only; duplicated error message */ +#define C_LAST 9 /* last error category */ + +#define SORTABLE(x) (!(NOTSORTABLE(x))) +#define NOTSORTABLE(x) (x <= C_NONSPEC) +/* + * Resources to count and print out the error categories + */ +extern char *class_table[]; +extern int class_count[]; + +#define nunknown class_count[C_UNKNOWN] +#define nignore class_count[C_IGNORE] +#define nsyncerrors class_count[C_SYNC] +#define ndiscard class_count[C_DISCARD] +#define nnonspec class_count[C_NONSPEC] +#define nthisfile class_count[C_THISFILE] +#define nnulled class_count[C_NULLED] +#define ntrue class_count[C_TRUE] +#define ndupl class_count[C_DUPL] + +/* places to put the error complaints */ + +#define TOTHEFILE 1 /* touch the file */ +#define TOSTDOUT 2 /* just print them out (ho-hum) */ + +FILE *errorfile; /* where error file comes from */ +FILE *queryfile; /* where the query responses from the user come from*/ + +extern char *currentfilename; +extern char *processname; +extern char *scriptname; + +extern boolean query; +extern boolean terse; +int inquire(); /* inquire for yes/no */ +/* + * codes for inquire() to return + */ +#define Q_NO 1 /* 'N' */ +#define Q_no 2 /* 'n' */ +#define Q_YES 3 /* 'Y' */ +#define Q_yes 4 /* 'y' */ + +int probethisfile(); +/* + * codes for probethisfile to return + */ +#define F_NOTEXIST 1 +#define F_NOTREAD 2 +#define F_NOTWRITE 3 +#define F_TOUCHIT 4 + +/* + * Describes attributes about a language + */ +struct lang_desc{ + char *lang_name; + char *lang_incomment; /* one of the following defines */ + char *lang_outcomment; /* one of the following defines */ +}; +extern struct lang_desc lang_table[]; + +#define CINCOMMENT "/*###" +#define COUTCOMMENT "%%%*/\n" +#define FINCOMMENT "C###" +#define FOUTCOMMENT "%%%\n" +#define NEWLINE "%%%\n" +#define PIINCOMMENT "(*###" +#define PIOUTCOMMENT "%%%*)\n" +#define LISPINCOMMENT ";###" +#define ASINCOMMENT "####" +#define RIINCOMMENT CINCOMMENT +#define RIOUTCOMMENT COUTCOMMENT +#define TROFFINCOMMENT ".\\\"###" +#define TROFFOUTCOMMENT NEWLINE +#define MOD2INCOMMENT "(*###" +#define MOD2OUTCOMMENT "%%%*)\n" +/* + * Defines and resources for determing if a given line + * is to be discarded because it refers to a file not to + * be touched, or if the function reference is to a + * function the user doesn't want recorded. + */ + +#define ERRORNAME "/.errorrc" +int nignored; +char **names_ignored; +/* + * Structure definition for a full error + */ +typedef struct edesc Edesc; +typedef Edesc *Eptr; + +struct edesc{ + Eptr error_next; /*linked together*/ + int error_lgtext; /* how many on the right hand side*/ + char **error_text; /* the right hand side proper*/ + Errorclass error_e_class; /* error category of this error*/ + Errorclass error_s_class; /* sub descriptor of error_e_class*/ + int error_language; /* the language for this error*/ + int error_position; /* oridinal position */ + int error_line; /* discovered line number*/ + int error_no; /* sequence number on input */ +}; +/* + * Resources for the true errors + */ +extern int nerrors; +extern Eptr er_head; +extern Eptr *errors; +/* + * Resources for each of the files mentioned + */ +extern int nfiles; +extern Eptr **files; /* array of pointers into errors*/ +boolean *touchedfiles; /* which files we touched */ +/* + * The langauge the compilation is in, as intuited from + * the flavor of error messages analyzed. + */ +extern int langauge; +extern char *currentfilename; +/* + * Functional forwards + */ +char *Calloc(); +char *strsave(); +char *clobberfirst(); +char lastchar(); +char firstchar(); +char next_lastchar(); +char **wordvsplice(); +int wordvcmp(); +boolean persperdexplode(); +/* + * Printing hacks + */ +char *plural(), *verbform(); diff --git a/usr.bin/error/filter.c b/usr.bin/error/filter.c new file mode 100644 index 0000000..40cf00d --- /dev/null +++ b/usr.bin/error/filter.c @@ -0,0 +1,194 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)filter.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "error.h" +#include "pathnames.h" + +char *lint_libs[] = { + IG_FILE1, + IG_FILE2, + IG_FILE3, + IG_FILE4, + 0 +}; +extern char* processname; +int lexsort(); +/* + * Read the file ERRORNAME of the names of functions in lint + * to ignore complaints about. + */ +getignored(auxname) + char *auxname; +{ + reg int i; + FILE *fyle; + char inbuffer[256]; + int uid; + char filename[128]; + char *username; + struct passwd *passwdentry; + + nignored = 0; + if (auxname == 0){ /* use the default */ + if ( (username = (char *)getlogin()) == NULL){ + username = "Unknown"; + uid = getuid(); + if ( (passwdentry = (struct passwd *)getpwuid(uid)) == NULL){ + return; + } + } else { + if ( (passwdentry = (struct passwd *)getpwnam(username)) == NULL) + return; + } + strcpy(filename, passwdentry->pw_dir); + (void)strcat(filename, ERRORNAME); + } else + (void)strcpy(filename, auxname); +#ifdef FULLDEBUG + printf("Opening file \"%s\" to read names to ignore.\n", + filename); +#endif + if ( (fyle = fopen(filename, "r")) == NULL){ +#ifdef FULLDEBUG + fprintf(stderr, "%s: Can't open file \"%s\"\n", + processname, filename); +#endif + return; + } + /* + * Make the first pass through the file, counting lines + */ + for (nignored = 0; fgets(inbuffer, 255, fyle) != NULL; nignored++) + continue; + names_ignored = (char **)Calloc(nignored+1, sizeof (char *)); + fclose(fyle); + if (freopen(filename, "r", fyle) == NULL){ +#ifdef FULLDEBUG + fprintf(stderr, "%s: Failure to open \"%s\" for second read.\n", + processname, filename); +#endif + nignored = 0; + return; + } + for (i=0; i < nignored && (fgets (inbuffer, 255, fyle) != NULL); i++){ + names_ignored[i] = strsave(inbuffer); + (void)substitute(names_ignored[i], '\n', '\0'); + } + qsort(names_ignored, nignored, sizeof *names_ignored, lexsort); +#ifdef FULLDEBUG + printf("Names to ignore follow.\n"); + for (i=0; i < nignored; i++){ + printf("\tIgnore: %s\n", names_ignored[i]); + } +#endif +} + +int lexsort(cpp1, cpp2) + char **cpp1, **cpp2; +{ + return(strcmp(*cpp1, *cpp2)); +} + +int search_ignore(key) + char *key; +{ + reg int ub, lb; + reg int halfway; + int order; + + if (nignored == 0) + return(-1); + for(lb = 0, ub = nignored - 1; ub >= lb; ){ + halfway = (ub + lb)/2; + if ( (order = strcmp(key, names_ignored[halfway])) == 0) + return(halfway); + if (order < 0) /*key is less than probe, throw away above*/ + ub = halfway - 1; + else + lb = halfway + 1; + } + return(-1); +} + +/* + * Tell if the error text is to be ignored. + * The error must have been canonicalized, with + * the file name the zeroth entry in the errorv, + * and the linenumber the second. + * Return the new categorization of the error class. + */ +Errorclass discardit(errorp) + reg Eptr errorp; +{ + int language; + reg int i; + Errorclass errorclass = errorp->error_e_class; + + switch(errorclass){ + case C_SYNC: + case C_NONSPEC: + case C_UNKNOWN: return(errorclass); + default: ; + } + if(errorp->error_lgtext < 2){ + return(C_NONSPEC); + } + language = errorp->error_language; + if(language == INLINT){ + if (errorclass != C_NONSPEC){ /* no file */ + for(i=0; lint_libs[i] != 0; i++){ + if (strcmp(errorp->error_text[0], lint_libs[i]) == 0){ + return(C_DISCARD); + } + } + } + /* check if the argument to the error message is to be ignored*/ + if (ispunct(lastchar(errorp->error_text[2]))) + clob_last(errorp->error_text[2], '\0'); + if (search_ignore(errorp->error_text[errorclass == C_NONSPEC ? 0 : 2]) >= 0){ + return(C_NULLED); + } + } + return(errorclass); +} diff --git a/usr.bin/error/input.c b/usr.bin/error/input.c new file mode 100644 index 0000000..a83013a --- /dev/null +++ b/usr.bin/error/input.c @@ -0,0 +1,548 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "error.h" + +int wordc; /* how long the current error message is */ +char **wordv; /* the actual error message */ + +int nerrors; +int language; + +Errorclass onelong(); +Errorclass cpp(); +Errorclass pccccom(); /* Portable C Compiler C Compiler */ +Errorclass richieccom(); /* Richie Compiler for 11 */ +Errorclass lint0(); +Errorclass lint1(); +Errorclass lint2(); +Errorclass lint3(); +Errorclass make(); +Errorclass f77(); +Errorclass pi(); +Errorclass ri(); +Errorclass troff(); +Errorclass mod2(); +/* + * Eat all of the lines in the input file, attempting to categorize + * them by their various flavors + */ +static char inbuffer[BUFSIZ]; + +eaterrors(r_errorc, r_errorv) + int *r_errorc; + Eptr **r_errorv; +{ + extern boolean piflag; + Errorclass errorclass = C_SYNC; + + for (;;){ + if (fgets(inbuffer, BUFSIZ, errorfile) == NULL) + break; + wordvbuild(inbuffer, &wordc, &wordv); + /* + * for convience, convert wordv to be 1 based, instead + * of 0 based. + */ + wordv -= 1; + if ( wordc > 0 && + ((( errorclass = onelong() ) != C_UNKNOWN) + || (( errorclass = cpp() ) != C_UNKNOWN) + || (( errorclass = pccccom() ) != C_UNKNOWN) + || (( errorclass = richieccom() ) != C_UNKNOWN) + || (( errorclass = lint0() ) != C_UNKNOWN) + || (( errorclass = lint1() ) != C_UNKNOWN) + || (( errorclass = lint2() ) != C_UNKNOWN) + || (( errorclass = lint3() ) != C_UNKNOWN) + || (( errorclass = make() ) != C_UNKNOWN) + || (( errorclass = f77() ) != C_UNKNOWN) + || ((errorclass = pi() ) != C_UNKNOWN) + || (( errorclass = ri() )!= C_UNKNOWN) + || (( errorclass = mod2() )!= C_UNKNOWN) + || (( errorclass = troff() )!= C_UNKNOWN)) + ) ; + else + errorclass = catchall(); + if (wordc) + erroradd(wordc, wordv+1, errorclass, C_UNKNOWN); + } +#ifdef FULLDEBUG + printf("%d errorentrys\n", nerrors); +#endif + arrayify(r_errorc, r_errorv, er_head); +} + +/* + * create a new error entry, given a zero based array and count + */ +erroradd(errorlength, errorv, errorclass, errorsubclass) + int errorlength; + char **errorv; + Errorclass errorclass; + Errorclass errorsubclass; +{ + reg Eptr newerror; + reg char *cp; + + if (errorclass == C_TRUE){ + /* check canonicalization of the second argument*/ + for(cp = errorv[1]; *cp && isdigit(*cp); cp++) + continue; + errorclass = (*cp == '\0') ? C_TRUE : C_NONSPEC; +#ifdef FULLDEBUG + if (errorclass != C_TRUE) + printf("The 2nd word, \"%s\" is not a number.\n", + errorv[1]); +#endif + } + if (errorlength > 0){ + newerror = (Eptr)Calloc(1, sizeof(Edesc)); + newerror->error_language = language; /* language is global */ + newerror->error_text = errorv; + newerror->error_lgtext = errorlength; + if (errorclass == C_TRUE) + newerror->error_line = atoi(errorv[1]); + newerror->error_e_class = errorclass; + newerror->error_s_class = errorsubclass; + switch(newerror->error_e_class = discardit(newerror)){ + case C_SYNC: nsyncerrors++; break; + case C_DISCARD: ndiscard++; break; + case C_NULLED: nnulled++; break; + case C_NONSPEC: nnonspec++; break; + case C_THISFILE: nthisfile++; break; + case C_TRUE: ntrue++; break; + case C_UNKNOWN: nunknown++; break; + case C_IGNORE: nignore++; break; + } + newerror->error_next = er_head; + er_head = newerror; + newerror->error_no = nerrors++; + } /* length > 0 */ +} + +Errorclass onelong() +{ + char **nwordv; + if ( (wordc == 1) && (language != INLD) ){ + /* + * We have either: + * a) file name from cc + * b) Assembler telling world that it is complaining + * c) Noise from make ("Stop.") + * c) Random noise + */ + wordc = 0; + if (strcmp(wordv[1], "Stop.") == 0){ + language = INMAKE; return(C_SYNC); + } + if (strcmp(wordv[1], "Assembler:") == 0){ + /* assembler always alerts us to what happened*/ + language = INAS; return(C_SYNC); + } else + if (strcmp(wordv[1], "Undefined:") == 0){ + /* loader complains about unknown symbols*/ + language = INLD; return(C_SYNC); + } + if (lastchar(wordv[1]) == ':'){ + /* cc tells us what file we are in */ + currentfilename = wordv[1]; + (void)substitute(currentfilename, ':', '\0'); + language = INCC; return(C_SYNC); + } + } else + if ( (wordc == 1) && (language == INLD) ){ + nwordv = (char **)Calloc(4, sizeof(char *)); + nwordv[0] = "ld:"; + nwordv[1] = wordv[1]; + nwordv[2] = "is"; + nwordv[3] = "undefined."; + wordc = 4; + wordv = nwordv - 1; + return(C_NONSPEC); + } else + if (wordc == 1){ + return(C_SYNC); + } + return(C_UNKNOWN); +} /* end of one long */ + +Errorclass cpp() +{ + /* + * Now attempt a cpp error message match + * Examples: + * ./morse.h: 23: undefined control + * morsesend.c: 229: MAGNIBBL: argument mismatch + * morsesend.c: 237: MAGNIBBL: argument mismatch + * test1.c: 6: undefined control + */ + if ( (language != INLD) /* loader errors have almost same fmt*/ + && (lastchar(wordv[1]) == ':') + && (isdigit(firstchar(wordv[2]))) + && (lastchar(wordv[2]) == ':') ){ + language = INCPP; + clob_last(wordv[1], '\0'); + clob_last(wordv[2], '\0'); + return(C_TRUE); + } + return(C_UNKNOWN); +} /*end of cpp*/ + +Errorclass pccccom() +{ + /* + * Now attempt a ccom error message match: + * Examples: + * "morsesend.c", line 237: operands of & have incompatible types + * "test.c", line 7: warning: old-fashioned initialization: use = + * "subdir.d/foo2.h", line 1: illegal initialization + */ + if ( (firstchar(wordv[1]) == '"') + && (lastchar(wordv[1]) == ',') + && (next_lastchar(wordv[1]) == '"') + && (strcmp(wordv[2],"line") == 0) + && (isdigit(firstchar(wordv[3]))) + && (lastchar(wordv[3]) == ':') ){ + clob_last(wordv[1], '\0'); /* drop last , */ + clob_last(wordv[1], '\0'); /* drop last " */ + wordv[1]++; /* drop first " */ + clob_last(wordv[3], '\0'); /* drop : on line number */ + wordv[2] = wordv[1]; /* overwrite "line" */ + wordv++; /*compensate*/ + wordc--; + currentfilename = wordv[1]; + language = INCC; + return(C_TRUE); + } + return(C_UNKNOWN); +} /* end of ccom */ +/* + * Do the error message from the Richie C Compiler for the PDP11, + * which has this source: + * + * if (filename[0]) + * fprintf(stderr, "%s:", filename); + * fprintf(stderr, "%d: ", line); + * + */ +Errorclass richieccom() +{ + reg char *cp; + reg char **nwordv; + char *file; + + if (lastchar(wordv[1]) == ':'){ + cp = wordv[1] + strlen(wordv[1]) - 1; + while (isdigit(*--cp)) + continue; + if (*cp == ':'){ + clob_last(wordv[1], '\0'); /* last : */ + *cp = '\0'; /* first : */ + file = wordv[1]; + nwordv = wordvsplice(1, wordc, wordv+1); + nwordv[0] = file; + nwordv[1] = cp + 1; + wordc += 1; + wordv = nwordv - 1; + language = INCC; + currentfilename = wordv[1]; + return(C_TRUE); + } + } + return(C_UNKNOWN); +} + +Errorclass lint0() +{ + reg char **nwordv; + char *line, *file; + /* + * Attempt a match for the new lint style normal compiler + * error messages, of the form + * + * printf("%s(%d): %s\n", filename, linenumber, message); + */ + if (wordc >= 2){ + if ( (lastchar(wordv[1]) == ':') + && (next_lastchar(wordv[1]) == ')') + ) { + clob_last(wordv[1], '\0'); /* colon */ + if (persperdexplode(wordv[1], &line, &file)){ + nwordv = wordvsplice(1, wordc, wordv+1); + nwordv[0] = file; /* file name */ + nwordv[1] = line; /* line number */ + wordc += 1; + wordv = nwordv - 1; + language = INLINT; + return(C_TRUE); + } + wordv[1][strlen(wordv[1])] = ':'; + } + } + return (C_UNKNOWN); +} + +Errorclass lint1() +{ + char *line1, *line2; + char *file1, *file2; + char **nwordv1, **nwordv2; + + /* + * Now, attempt a match for the various errors that lint + * can complain about. + * + * Look first for type 1 lint errors + */ + if (wordc > 1 && strcmp(wordv[wordc-1], "::") == 0){ + /* + * %.7s, arg. %d used inconsistently %s(%d) :: %s(%d) + * %.7s value used inconsistently %s(%d) :: %s(%d) + * %.7s multiply declared %s(%d) :: %s(%d) + * %.7s value declared inconsistently %s(%d) :: %s(%d) + * %.7s function value type must be declared before use %s(%d) :: %s(%d) + */ + language = INLINT; + if (wordc > 2 + && (persperdexplode(wordv[wordc], &line2, &file2)) + && (persperdexplode(wordv[wordc-2], &line1, &file1)) ){ + nwordv1 = wordvsplice(2, wordc, wordv+1); + nwordv2 = wordvsplice(2, wordc, wordv+1); + nwordv1[0] = file1; nwordv1[1] = line1; + erroradd(wordc+2, nwordv1, C_TRUE, C_DUPL); /* takes 0 based*/ + nwordv2[0] = file2; nwordv2[1] = line2; + wordc = wordc + 2; + wordv = nwordv2 - 1; /* 1 based */ + return(C_TRUE); + } + } + return(C_UNKNOWN); +} /* end of lint 1*/ + +Errorclass lint2() +{ + char *file; + char *line; + char **nwordv; + /* + * Look for type 2 lint errors + * + * %.7s used( %s(%d) ), but not defined + * %.7s defined( %s(%d) ), but never used + * %.7s declared( %s(%d) ), but never used or defined + * + * bufp defined( "./metric.h"(10) ), but never used + */ + if ( (lastchar(wordv[2]) == '(' /* ')' */ ) + && (strcmp(wordv[4], "),") == 0) ){ + language = INLINT; + if (persperdexplode(wordv[3], &line, &file)){ + nwordv = wordvsplice(2, wordc, wordv+1); + nwordv[0] = file; nwordv[1] = line; + wordc = wordc + 2; + wordv = nwordv - 1; /* 1 based */ + return(C_TRUE); + } + } + return(C_UNKNOWN); +} /* end of lint 2*/ + +char *Lint31[4] = {"returns", "value", "which", "is"}; +char *Lint32[6] = {"value", "is", "used,", "but", "none", "returned"}; +Errorclass lint3() +{ + if ( (wordvcmp(wordv+2, 4, Lint31) == 0) + || (wordvcmp(wordv+2, 6, Lint32) == 0) ){ + language = INLINT; + return(C_NONSPEC); + } + return(C_UNKNOWN); +} + +/* + * Special word vectors for use by F77 recognition + */ +char *F77_fatal[3] = {"Compiler", "error", "line"}; +char *F77_error[3] = {"Error", "on", "line"}; +char *F77_warning[3] = {"Warning", "on", "line"}; +char *F77_no_ass[3] = {"Error.","No","assembly."}; +f77() +{ + char **nwordv; + /* + * look for f77 errors: + * Error messages from /usr/src/cmd/f77/error.c, with + * these printf formats: + * + * Compiler error line %d of %s: %s + * Error on line %d of %s: %s + * Warning on line %d of %s: %s + * Error. No assembly. + */ + if (wordc == 3 && wordvcmp(wordv+1, 3, F77_no_ass) == 0) { + wordc = 0; + return(C_SYNC); + } + if (wordc < 6) + return(C_UNKNOWN); + if ( (lastchar(wordv[6]) == ':') + &&( + (wordvcmp(wordv+1, 3, F77_fatal) == 0) + || (wordvcmp(wordv+1, 3, F77_error) == 0) + || (wordvcmp(wordv+1, 3, F77_warning) == 0) ) + ){ + language = INF77; + nwordv = wordvsplice(2, wordc, wordv+1); + nwordv[0] = wordv[6]; + clob_last(nwordv[0],'\0'); + nwordv[1] = wordv[4]; + wordc += 2; + wordv = nwordv - 1; /* 1 based */ + return(C_TRUE); + } + return(C_UNKNOWN); +} /* end of f77 */ + +char *Make_Croak[3] = {"***", "Error", "code"}; +char *Make_NotRemade[5] = {"not", "remade", "because", "of", "errors"}; +Errorclass make() +{ + if (wordvcmp(wordv+1, 3, Make_Croak) == 0){ + language = INMAKE; + return(C_SYNC); + } + if (wordvcmp(wordv+2, 5, Make_NotRemade) == 0){ + language = INMAKE; + return(C_SYNC); + } + return(C_UNKNOWN); +} +Errorclass ri() +{ +/* + * Match an error message produced by ri; here is the + * procedure yanked from the distributed version of ri + * April 24, 1980. + * + * serror(str, x1, x2, x3) + * char str[]; + * char *x1, *x2, *x3; + * { + * extern int yylineno; + * + * putc('"', stdout); + * fputs(srcfile, stdout); + * putc('"', stdout); + * fprintf(stdout, " %d: ", yylineno); + * fprintf(stdout, str, x1, x2, x3); + * fprintf(stdout, "\n"); + * synerrs++; + * } + */ + if ( (firstchar(wordv[1]) == '"') + &&(lastchar(wordv[1]) == '"') + &&(lastchar(wordv[2]) == ':') + &&(isdigit(firstchar(wordv[2]))) ){ + clob_last(wordv[1], '\0'); /* drop the last " */ + wordv[1]++; /* skip over the first " */ + clob_last(wordv[2], '\0'); + language = INRI; + return(C_TRUE); + } + return(C_UNKNOWN); +} + +Errorclass catchall() +{ + /* + * Catches random things. + */ + language = INUNKNOWN; + return(C_NONSPEC); +} /* end of catch all*/ + +Errorclass troff() +{ + /* + * troff source error message, from eqn, bib, tbl... + * Just like pcc ccom, except uses `' + */ + if ( (firstchar(wordv[1]) == '`') + && (lastchar(wordv[1]) == ',') + && (next_lastchar(wordv[1]) == '\'') + && (strcmp(wordv[2],"line") == 0) + && (isdigit(firstchar(wordv[3]))) + && (lastchar(wordv[3]) == ':') ){ + clob_last(wordv[1], '\0'); /* drop last , */ + clob_last(wordv[1], '\0'); /* drop last " */ + wordv[1]++; /* drop first " */ + clob_last(wordv[3], '\0'); /* drop : on line number */ + wordv[2] = wordv[1]; /* overwrite "line" */ + wordv++; /*compensate*/ + currentfilename = wordv[1]; + language = INTROFF; + return(C_TRUE); + } + return(C_UNKNOWN); +} +Errorclass mod2() +{ + /* + * for decwrl modula2 compiler (powell) + */ + if ( ( (strcmp(wordv[1], "!!!") == 0) /* early version */ + ||(strcmp(wordv[1], "File") == 0)) /* later version */ + && (lastchar(wordv[2]) == ',') /* file name */ + && (strcmp(wordv[3], "line") == 0) + && (isdigit(firstchar(wordv[4]))) /* line number */ + && (lastchar(wordv[4]) == ':') /* line number */ + ){ + clob_last(wordv[2], '\0'); /* drop last , on file name */ + clob_last(wordv[4], '\0'); /* drop last : on line number */ + wordv[3] = wordv[2]; /* file name on top of "line" */ + wordv += 2; + wordc -= 2; + currentfilename = wordv[1]; + language = INMOD2; + return(C_TRUE); + } + return(C_UNKNOWN); +} diff --git a/usr.bin/error/main.c b/usr.bin/error/main.c new file mode 100644 index 0000000..fe20c37 --- /dev/null +++ b/usr.bin/error/main.c @@ -0,0 +1,287 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include "error.h" +#include "pathnames.h" + +int nerrors = 0; +Eptr er_head; +Eptr *errors; + +int nfiles = 0; +Eptr **files; /* array of pointers into errors*/ +int language = INCC; + +char *currentfilename = "????"; +char *processname; +char im_on[] = _PATH_TTY; /* my tty name */ + +boolean query = FALSE; /* query the operator if touch files */ +boolean notouch = FALSE; /* don't touch ANY files */ +boolean piflag = FALSE; /* this is not pi */ +boolean terse = FALSE; /* Terse output */ + +char *suffixlist = ".*"; /* initially, can touch any file */ + +int errorsort(); +void onintr(); +/* + * error [-I ignorename] [-n] [-q] [-t suffixlist] [-s] [-v] [infile] + * + * -T: terse output + * + * -I: the following name, `ignorename' contains a list of + * function names that are not to be treated as hard errors. + * Default: ~/.errorsrc + * + * -n: don't touch ANY files! + * + * -q: The user is to be queried before touching each + * file; if not specified, all files with hard, non + * ignorable errors are touched (assuming they can be). + * + * -t: touch only files ending with the list of suffices, each + * suffix preceded by a dot. + * eg, -t .c.y.l + * will touch only files ending with .c, .y or .l + * + * -s: print a summary of the error's categories. + * + * -v: after touching all files, overlay vi(1), ex(1) or ed(1) + * on top of error, entered in the first file with + * an error in it, with the appropriate editor + * set up to use the "next" command to get the other + * files containing errors. + * + * -p: (obsolete: for older versions of pi without bug + * fix regarding printing out the name of the main file + * with an error in it) + * Take the following argument and use it as the name of + * the pascal source file, suffix .p + * + * -E: show the errors in sorted order; intended for + * debugging. + * + * -S: show the errors in unsorted order + * (as they come from the error file) + * + * infile: The error messages come from this file. + * Default: stdin + */ +main(argc, argv) + int argc; + char *argv[]; +{ + char *cp; + char *ignorename = 0; + int ed_argc; + char **ed_argv; /*return from touchfiles*/ + boolean show_errors = FALSE; + boolean Show_Errors = FALSE; + boolean pr_summary = FALSE; + boolean edit_files = FALSE; + + processname = argv[0]; + + errorfile = stdin; + if (argc > 1) for(; (argc > 1) && (argv[1][0] == '-'); argc--, argv++){ + for (cp = argv[1] + 1; *cp; cp++) switch(*cp){ + default: + fprintf(stderr, "%s: -%c: Unknown flag\n", + processname, *cp); + break; + + case 'n': notouch = TRUE; break; + case 'q': query = TRUE; break; + case 'S': Show_Errors = TRUE; break; + case 's': pr_summary = TRUE; break; + case 'v': edit_files = TRUE; break; + case 'T': terse = TRUE; break; + case 't': + *cp-- = 0; argv++; argc--; + if (argc > 1){ + suffixlist = argv[1]; + } + break; + case 'I': /*ignore file name*/ + *cp-- = 0; argv++; argc--; + if (argc > 1) + ignorename = argv[1]; + break; + } + } + if (notouch) + suffixlist = 0; + if (argc > 1){ + if (argc > 3){ + fprintf(stderr, "%s: Only takes 0 or 1 arguments\n", + processname); + exit(3); + } + if ( (errorfile = fopen(argv[1], "r")) == NULL){ + fprintf(stderr, "%s: %s: No such file or directory for reading errors.\n", + processname, argv[1]); + exit(4); + } + } + if ( (queryfile = fopen(im_on, "r")) == NULL){ + if (query){ + fprintf(stderr, + "%s: Can't open \"%s\" to query the user.\n", + processname, im_on); + exit(9); + } + } + if (signal(SIGINT, onintr) == SIG_IGN) + signal(SIGINT, SIG_IGN); + if (signal(SIGTERM, onintr) == SIG_IGN) + signal(SIGTERM, SIG_IGN); + getignored(ignorename); + eaterrors(&nerrors, &errors); + if (Show_Errors) + printerrors(TRUE, nerrors, errors); + qsort(errors, nerrors, sizeof(Eptr), errorsort); + if (show_errors) + printerrors(FALSE, nerrors, errors); + findfiles(nerrors, errors, &nfiles, &files); +#define P(msg, arg) fprintf(stdout, msg, arg) + if (pr_summary){ + if (nunknown) + P("%d Errors are unclassifiable.\n", nunknown); + if (nignore) + P("%d Errors are classifiable, but totally discarded.\n",nignore); + if (nsyncerrors) + P("%d Errors are synchronization errors.\n", nsyncerrors); + if (nignore) + P("%d Errors are discarded because they refer to sacrosinct files.\n", ndiscard); + if (nnulled) + P("%d Errors are nulled because they refer to specific functions.\n", nnulled); + if (nnonspec) + P("%d Errors are not specific to any file.\n", nnonspec); + if (nthisfile) + P("%d Errors are specific to a given file, but not to a line.\n", nthisfile); + if (ntrue) + P("%d Errors are true errors, and can be inserted into the files.\n", ntrue); + } + filenames(nfiles, files); + fflush(stdout); + if (touchfiles(nfiles, files, &ed_argc, &ed_argv) && edit_files) + forkvi(ed_argc, ed_argv); +} + +forkvi(argc, argv) + int argc; + char **argv; +{ + if (query){ + switch(inquire(terse + ? "Edit? " + : "Do you still want to edit the files you touched? ")){ + case Q_NO: + case Q_no: + return; + default: + break; + } + } + /* + * ed_agument's first argument is + * a vi/ex compatabile search argument + * to find the first occurance of ### + */ + try("vi", argc, argv); + try("ex", argc, argv); + try("ed", argc-1, argv+1); + fprintf(stdout, "Can't find any editors.\n"); +} + +try(name, argc, argv) + char *name; + int argc; + char **argv; +{ + argv[0] = name; + wordvprint(stdout, argc, argv); + fprintf(stdout, "\n"); + fflush(stderr); + fflush(stdout); + sleep(2); + if (freopen(im_on, "r", stdin) == NULL) + return; + if (freopen(im_on, "w", stdout) == NULL) + return; + execvp(name, argv); +} + +int errorsort(epp1, epp2) + Eptr *epp1, *epp2; +{ + reg Eptr ep1, ep2; + int order; + /* + * Sort by: + * 1) synchronization, non specific, discarded errors first; + * 2) nulled and true errors last + * a) grouped by similar file names + * 1) grouped in ascending line number + */ + ep1 = *epp1; ep2 = *epp2; + if (ep1 == 0 || ep2 == 0) + return(0); + if ( (NOTSORTABLE(ep1->error_e_class)) ^ (NOTSORTABLE(ep2->error_e_class))){ + return(NOTSORTABLE(ep1->error_e_class) ? -1 : 1); + } + if (NOTSORTABLE(ep1->error_e_class)) /* then both are */ + return(ep1->error_no - ep2->error_no); + order = strcmp(ep1->error_text[0], ep2->error_text[0]); + if (order == 0){ + return(ep1->error_line - ep2->error_line); + } + return(order); +} diff --git a/usr.bin/error/pathnames.h b/usr.bin/error/pathnames.h new file mode 100644 index 0000000..add09fb --- /dev/null +++ b/usr.bin/error/pathnames.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define IG_FILE1 "llib-lc" +#define IG_FILE2 "llib-port" +#define IG_FILE3 "/usr/lib/llib-lc" +#define IG_FILE4 "/usr/lib/llib-port" +#undef _PATH_TMP +#define _PATH_TMP "/tmp/ErrorXXXXXX" diff --git a/usr.bin/error/pi.c b/usr.bin/error/pi.c new file mode 100644 index 0000000..67778a4 --- /dev/null +++ b/usr.bin/error/pi.c @@ -0,0 +1,404 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)pi.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include "error.h" + +extern char *currentfilename; +static char *c_linenumber; +static char *unk_hdr[] = {"In", "program", "???"}; +static char **c_header = &unk_hdr[0]; + +/* + * Attempt to handle error messages produced by pi (and by pc) + * + * problem #1: There is no file name available when a file does not + * use a #include; this will have to be given to error + * in the command line. + * problem #2: pi doesn't always tell you what line number + * a error refers to; for example during the tree + * walk phase of code generation and error detection, + * an error can refer to "variable foo in procedure bletch" + * without giving a line number + * problem #3: line numbers, when available, are attached to + * the source line, along with the source line itself + * These line numbers must be extracted, and + * the source line thrown away. + * problem #4: Some error messages produce more than one line number + * on the same message. + * There are only two (I think): + * %s undefined on line%s + * %s improperly used on line%s + * here, the %s makes line plural or singular. + * + * Here are the error strings used in pi version 1.2 that can refer + * to a file name or line number: + * + * Multiply defined label in case, lines %d and %d + * Goto %s from line %d is into a structured statement + * End matched %s on line %d + * Inserted keyword end matching %s on line %d + * + * Here are the general pi patterns recognized: + * define piptr == -.*^-.* + * define msg = .* + * define digit = [0-9] + * definename = .* + * define date_format letter*3 letter*3 (digit | (digit digit)) + * (digit | (digit digit)):digit*2 digit*4 + * + * {e,E} (piptr) (msg) Encounter an error during textual scan + * E {digit}* - (msg) Have an error message that refers to a new line + * E - msg Have an error message that refers to current + * function, program or procedure + * (date_format) (name): When switch compilation files + * ... (msg) When refer to the previous line + * 'In' ('procedure'|'function'|'program') (name): + * pi is now complaining about 2nd pass errors. + * + * Here is the output from a compilation + * + * + * 2 var i:integer; + * e --------------^--- Inserted ';' + * E 2 - All variables must be declared in one var part + * E 5 - Include filename must end in .i + * Mon Apr 21 15:56 1980 test.h: + * 2 begin + * e ------^--- Inserted ';' + * Mon Apr 21 16:06 1980 test.p: + * E 2 - Function type must be specified + * 6 procedure foo(var x:real); + * e ------^--- Inserted ';' + * In function bletch: + * E - No assignment to the function variable + * w - variable x is never used + * E 6 - foo is already defined in this block + * In procedure foo: + * w - variable x is neither used nor set + * 9 z : = 23; + * E --------------^--- Undefined variable + * 10 y = [1]; + * e ----------------^--- Inserted ':' + * 13 z := 345.; + * e -----------------------^--- Digits required after decimal point + * E 10 - Constant set involved in non set context + * E 11 - Type clash: real is incompatible with integer + * ... Type of expression clashed with type of variable in assignment + * E 12 - Parameter type not identical to type of var parameter x of foo + * In program mung: + * w - variable y is never used + * w - type foo is never used + * w - function bletch is never used + * E - z undefined on lines 9 13 + */ +char *Months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct","Nov", "Dec", + 0 +}; +char *Days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0 +}; +char *Piroutines[] = { + "program", "function", "procedure", 0 +}; + + +static boolean structured, multiple; + +char *pi_Endmatched[] = {"End", "matched"}; +char *pi_Inserted[] = {"Inserted", "keyword", "end", "matching"}; + +char *pi_multiple[] = {"Mutiply", "defined", "label", "in", "case,", "line"}; +char *pi_structured[] = {"is", "into", "a", "structured", "statement"}; + +char *pi_und1[] = {"undefined", "on", "line"}; +char *pi_und2[] = {"undefined", "on", "lines"}; +char *pi_imp1[] = {"improperly", "used", "on", "line"}; +char *pi_imp2[] = {"improperly", "used", "on", "lines"}; + +boolean alldigits(string) + reg char *string; +{ + for (; *string && isdigit(*string); string++) + continue; + return(*string == '\0'); +} +boolean instringset(member, set) + char *member; + reg char **set; +{ + for(; *set; set++){ + if (strcmp(*set, member) == 0) + return(TRUE); + } + return(FALSE); +} + +boolean isdateformat(wordc, wordv) + int wordc; + char **wordv; +{ + return( + (wordc == 5) + && (instringset(wordv[0], Days)) + && (instringset(wordv[1], Months)) + && (alldigits(wordv[2])) + && (alldigits(wordv[4])) ); +} + +boolean piptr(string) + reg char *string; +{ + if (*string != '-') + return(FALSE); + while (*string && *string == '-') + string++; + if (*string != '^') + return(FALSE); + string++; + while (*string && *string == '-') + string++; + return(*string == '\0'); +} + +extern int wordc; +extern char **wordv; + +Errorclass pi() +{ + char **nwordv; + + if (wordc < 2) + return (C_UNKNOWN); + if ( ( strlen(wordv[1]) == 1) + && ( (wordv[1][0] == 'e') || (wordv[1][0] == 'E') ) + && ( piptr(wordv[2]) ) + ) { + boolean longpiptr = 0; + /* + * We have recognized a first pass error of the form: + * letter ------^---- message + * + * turn into an error message of the form: + * + * file line 'pascal errortype' letter \n |---- message + * or of the form: + * file line letter |---- message + * when there are strlen("(*[pi]") or more + * preceding '-' on the error pointer. + * + * Where the | is intended to be a down arrow, so that + * the pi error messages can be inserted above the + * line in error, instead of below. (All of the other + * langauges put thier messages before the source line, + * instead of after it as does pi.) + * + * where the pointer to the error has been truncated + * by 6 characters to account for the fact that + * the pointer points into a tab preceded input line. + */ + language = INPI; + (void)substitute(wordv[2], '^', '|'); + longpiptr = position(wordv[2],'|') > (6+8); + nwordv = wordvsplice(longpiptr ? 2 : 4, wordc, wordv+1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = strsave(c_linenumber); + if (!longpiptr){ + nwordv[2] = "pascal errortype"; + nwordv[3] = wordv[1]; + nwordv[4] = strsave("%%%\n"); + if (strlen(nwordv[5]) > (8-2)) /* this is the pointer */ + nwordv[5] += (8-2); /* bump over 6 characters */ + } + wordv = nwordv - 1; /* convert to 1 based */ + wordc += longpiptr ? 2 : 4; + return(C_TRUE); + } + if ( (wordc >= 4) + && (strlen(wordv[1]) == 1) + && ( (*wordv[1] == 'E') || (*wordv[1] == 'w') || (*wordv[1] == 'e') ) + && (alldigits(wordv[2])) + && (strlen(wordv[3]) == 1) + && (wordv[3][0] == '-') + ){ + /* + * Message of the form: letter linenumber - message + * Turn into form: filename linenumber letter - message + */ + language = INPI; + nwordv = wordvsplice(1, wordc, wordv + 1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = wordv[2]; + nwordv[2] = wordv[1]; + c_linenumber = wordv[2]; + wordc += 1; + wordv = nwordv - 1; + return(C_TRUE); + } + if ( (wordc >= 3) + && (strlen(wordv[1]) == 1) + && ( (*(wordv[1]) == 'E') || (*(wordv[1]) == 'w') || (*(wordv[1]) == 'e') ) + && (strlen(wordv[2]) == 1) + && (wordv[2][0] == '-') + ) { + /* + * Message of the form: letter - message + * This happens only when we are traversing the tree + * during the second pass of pi, and discover semantic + * errors. + * + * We have already (presumably) saved the header message + * and can now construct a nulled error message for the + * current file. + * + * Turns into a message of the form: + * filename (header) letter - message + * + * First, see if it is a message referring to more than + * one line number. Only of the form: + * %s undefined on line%s + * %s improperly used on line%s + */ + boolean undefined = 0; + int wordindex; + + language = INPI; + if ( (undefined = (wordvcmp(wordv+2, 3, pi_und1) == 0) ) + || (undefined = (wordvcmp(wordv+2, 3, pi_und2) == 0) ) + || (wordvcmp(wordv+2, 4, pi_imp1) == 0) + || (wordvcmp(wordv+2, 4, pi_imp2) == 0) + ){ + for (wordindex = undefined ? 5 : 6; wordindex <= wordc; + wordindex++){ + nwordv = wordvsplice(2, undefined ? 2 : 3, wordv+1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = wordv[wordindex]; + if (wordindex != wordc) + erroradd(undefined ? 4 : 5, nwordv, + C_TRUE, C_UNKNOWN); + } + wordc = undefined ? 4 : 5; + wordv = nwordv - 1; + return(C_TRUE); + } + + nwordv = wordvsplice(1+3, wordc, wordv+1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = strsave(c_header[0]); + nwordv[2] = strsave(c_header[1]); + nwordv[3] = strsave(c_header[2]); + wordv = nwordv - 1; + wordc += 1 + 3; + return(C_THISFILE); + } + if (strcmp(wordv[1], "...") == 0){ + /* + * have a continuation error message + * of the form: ... message + * Turn into form : filename linenumber message + */ + language = INPI; + nwordv = wordvsplice(1, wordc, wordv+1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = strsave(c_linenumber); + wordv = nwordv - 1; + wordc += 1; + return(C_TRUE); + } + if( (wordc == 6) + && (lastchar(wordv[6]) == ':') + && (isdateformat(5, wordv + 1)) + ){ + /* + * Have message that tells us we have changed files + */ + language = INPI; + currentfilename = strsave(wordv[6]); + clob_last(currentfilename, '\0'); + return(C_SYNC); + } + if( (wordc == 3) + && (strcmp(wordv[1], "In") == 0) + && (lastchar(wordv[3]) == ':') + && (instringset(wordv[2], Piroutines)) + ) { + language = INPI; + c_header = wordvsplice(0, wordc, wordv+1); + return(C_SYNC); + } + /* + * now, check for just the line number followed by the text + */ + if (alldigits(wordv[1])){ + language = INPI; + c_linenumber = wordv[1]; + return(C_IGNORE); + } + /* + * Attempt to match messages refering to a line number + * + * Multiply defined label in case, lines %d and %d + * Goto %s from line %d is into a structured statement + * End matched %s on line %d + * Inserted keyword end matching %s on line %d + */ + multiple = structured = 0; + if ( + ( (wordc == 6) && (wordvcmp(wordv+1, 2, pi_Endmatched) == 0)) + || ( (wordc == 8) && (wordvcmp(wordv+1, 4, pi_Inserted) == 0)) + || ( multiple = ((wordc == 9) && (wordvcmp(wordv+1,6, pi_multiple) == 0) ) ) + || ( structured = ((wordc == 10) && (wordvcmp(wordv+6,5, pi_structured) == 0 ) )) + ){ + language = INPI; + nwordv = wordvsplice(2, wordc, wordv+1); + nwordv[0] = strsave(currentfilename); + nwordv[1] = structured ? wordv [5] : wordv[wordc]; + wordc += 2; + wordv = nwordv - 1; + if (!multiple) + return(C_TRUE); + erroradd(wordc, nwordv, C_TRUE, C_UNKNOWN); + nwordv = wordvsplice(0, wordc, nwordv); + nwordv[1] = wordv[wordc - 2]; + return(C_TRUE); + } + return(C_UNKNOWN); +} diff --git a/usr.bin/error/subr.c b/usr.bin/error/subr.c new file mode 100644 index 0000000..6346e04 --- /dev/null +++ b/usr.bin/error/subr.c @@ -0,0 +1,423 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "error.h" +/* + * Arrayify a list of rules + */ +arrayify(e_length, e_array, header) + int *e_length; + Eptr **e_array; + Eptr header; +{ + reg Eptr errorp; + reg Eptr *array; + reg int listlength; + reg int listindex; + + for (errorp = header, listlength = 0; + errorp; errorp = errorp->error_next, listlength++) + continue; + array = (Eptr*)Calloc(listlength+1, sizeof (Eptr)); + for(listindex = 0, errorp = header; + listindex < listlength; + listindex++, errorp = errorp->error_next){ + array[listindex] = errorp; + errorp->error_position = listindex; + } + array[listindex] = (Eptr)0; + *e_length = listlength; + *e_array = array; +} + +/*VARARGS1*/ +error(msg, a1, a2, a3) + char *msg; +{ + fprintf(stderr, "Error: "); + fprintf(stderr, msg, a1, a2, a3); + fprintf(stderr, "\n"); + fflush(stdout); + fflush(stderr); + exit(6); +} +/*ARGSUSED*/ +char *Calloc(nelements, size) + int nelements; + int size; +{ + char *back; + if ( (back = (char *)calloc(nelements, size)) == (char *)NULL){ + error("Ran out of memory.\n"); + exit(1); + } + return(back); +} + +char *strsave(instring) + char *instring; +{ + char *outstring; + (void)strcpy(outstring = (char *)Calloc(1, strlen(instring) + 1), + instring); + return(outstring); +} +/* + * find the position of a given character in a string + * (one based) + */ +int position(string, ch) + reg char *string; + reg char ch; +{ + reg int i; + if (string) + for (i=1; *string; string++, i++){ + if (*string == ch) + return(i); + } + return(-1); +} +/* + * clobber the first occurance of ch in string by the new character + */ +char *substitute(string, chold, chnew) + char *string; + char chold, chnew; +{ + reg char *cp = string; + + if (cp) + while (*cp){ + if (*cp == chold){ + *cp = chnew; + break; + } + cp++; + } + return(string); +} + +char lastchar(string) + char *string; +{ + int length; + if (string == 0) return('\0'); + length = strlen(string); + if (length >= 1) + return(string[length-1]); + else + return('\0'); +} + +char firstchar(string) + char *string; +{ + if (string) + return(string[0]); + else + return('\0'); +} + +char next_lastchar(string) + char *string; +{ + int length; + if (string == 0) return('\0'); + length = strlen(string); + if (length >= 2) + return(string[length - 2]); + else + return('\0'); +} + +clob_last(string, newstuff) + char *string, newstuff; +{ + int length = 0; + if (string) + length = strlen(string); + if (length >= 1) + string[length - 1] = newstuff; +} + +/* + * parse a string that is the result of a format %s(%d) + * return TRUE if this is of the proper format + */ +boolean persperdexplode(string, r_perd, r_pers) + char *string; + char **r_perd, **r_pers; +{ + reg char *cp; + int length = 0; + + if (string) + length = strlen(string); + if ( (length >= 4) + && (string[length - 1] == ')' ) ){ + for (cp = &string[length - 2]; + (isdigit(*cp)) && (*cp != '('); + --cp) + continue; + if (*cp == '('){ + string[length - 1] = '\0'; /* clobber the ) */ + *r_perd = strsave(cp+1); + string[length - 1] = ')'; + *cp = '\0'; /* clobber the ( */ + *r_pers = strsave(string); + *cp = '('; + return(TRUE); + } + } + return(FALSE); +} +/* + * parse a quoted string that is the result of a format \"%s\"(%d) + * return TRUE if this is of the proper format + */ +boolean qpersperdexplode(string, r_perd, r_pers) + char *string; + char **r_perd, **r_pers; +{ + reg char *cp; + int length = 0; + + if (string) + length = strlen(string); + if ( (length >= 4) + && (string[length - 1] == ')' ) ){ + for (cp = &string[length - 2]; + (isdigit(*cp)) && (*cp != '('); + --cp) + continue; + if (*cp == '(' && *(cp - 1) == '"'){ + string[length - 1] = '\0'; + *r_perd = strsave(cp+1); + string[length - 1] = ')'; + *(cp - 1) = '\0'; /* clobber the " */ + *r_pers = strsave(string + 1); + *(cp - 1) = '"'; + return(TRUE); + } + } + return(FALSE); +} + +static char cincomment[] = CINCOMMENT; +static char coutcomment[] = COUTCOMMENT; +static char fincomment[] = FINCOMMENT; +static char foutcomment[] = FOUTCOMMENT; +static char newline[] = NEWLINE; +static char piincomment[] = PIINCOMMENT; +static char pioutcomment[] = PIOUTCOMMENT; +static char lispincomment[] = LISPINCOMMENT; +static char riincomment[] = RIINCOMMENT; +static char rioutcomment[] = RIOUTCOMMENT; +static char troffincomment[] = TROFFINCOMMENT; +static char troffoutcomment[] = TROFFOUTCOMMENT; +static char mod2incomment[] = MOD2INCOMMENT; +static char mod2outcomment[] = MOD2OUTCOMMENT; + +struct lang_desc lang_table[] = { + /*INUNKNOWN 0*/ "unknown", cincomment, coutcomment, + /*INCPP 1*/ "cpp", cincomment, coutcomment, + /*INCC 2*/ "cc", cincomment, coutcomment, + /*INAS 3*/ "as", ASINCOMMENT, newline, + /*INLD 4*/ "ld", cincomment, coutcomment, + /*INLINT 5*/ "lint", cincomment, coutcomment, + /*INF77 6*/ "f77", fincomment, foutcomment, + /*INPI 7*/ "pi", piincomment, pioutcomment, + /*INPC 8*/ "pc", piincomment, pioutcomment, + /*INFRANZ 9*/ "franz",lispincomment, newline, + /*INLISP 10*/ "lisp", lispincomment, newline, + /*INVAXIMA 11*/ "vaxima",lispincomment,newline, + /*INRATFOR 12*/ "ratfor",fincomment, foutcomment, + /*INLEX 13*/ "lex", cincomment, coutcomment, + /*INYACC 14*/ "yacc", cincomment, coutcomment, + /*INAPL 15*/ "apl", ".lm", newline, + /*INMAKE 16*/ "make", ASINCOMMENT, newline, + /*INRI 17*/ "ri", riincomment, rioutcomment, + /*INTROFF 18*/ "troff",troffincomment,troffoutcomment, + /*INMOD2 19*/ "mod2", mod2incomment, mod2outcomment, + 0, 0, 0 +}; + +printerrors(look_at_subclass, errorc, errorv) + boolean look_at_subclass; + int errorc; + Eptr errorv[]; +{ + reg int i; + reg Eptr errorp; + + for (errorp = errorv[i = 0]; i < errorc; errorp = errorv[++i]){ + if (errorp->error_e_class == C_IGNORE) + continue; + if (look_at_subclass && errorp->error_s_class == C_DUPL) + continue; + printf("Error %d, (%s error) [%s], text = \"", + i, + class_table[errorp->error_e_class], + lang_table[errorp->error_language].lang_name); + wordvprint(stdout,errorp->error_lgtext,errorp->error_text); + printf("\"\n"); + } +} + +wordvprint(fyle, wordc, wordv) + FILE *fyle; + int wordc; + char *wordv[]; +{ + int i; + char *sep = ""; + + for(i = 0; i < wordc; i++) + if (wordv[i]) { + fprintf(fyle, "%s%s",sep,wordv[i]); + sep = " "; + } +} + +/* + * Given a string, parse it into a number of words, and build + * a wordc wordv combination pointing into it. + */ +wordvbuild(string, r_wordc, r_wordv) + char *string; + int *r_wordc; + char ***r_wordv; +{ + reg char *cp; + char *saltedbuffer; + char **wordv; + int wordcount; + int wordindex; + + saltedbuffer = strsave(string); + for (wordcount = 0, cp = saltedbuffer; *cp; wordcount++){ + while (*cp && isspace(*cp)) + cp++; + if (*cp == 0) + break; + while (!isspace(*cp)) + cp++; + } + wordv = (char **)Calloc(wordcount + 1, sizeof (char *)); + for (cp=saltedbuffer,wordindex=0; wordcount; wordindex++,--wordcount){ + while (*cp && isspace(*cp)) + cp++; + if (*cp == 0) + break; + wordv[wordindex] = cp; + while(!isspace(*cp)) + cp++; + *cp++ = '\0'; + } + if (wordcount != 0) + error("Initial miscount of the number of words in a line\n"); + wordv[wordindex] = (char *)0; +#ifdef FULLDEBUG + for (wordcount = 0; wordcount < wordindex; wordcount++) + printf("Word %d = \"%s\"\n", wordcount, wordv[wordcount]); + printf("\n"); +#endif + *r_wordc = wordindex; + *r_wordv = wordv; +} +/* + * Compare two 0 based wordvectors + */ +int wordvcmp(wordv1, wordc, wordv2) + char **wordv1; + int wordc; + char **wordv2; +{ + reg int i; + int back; + for (i = 0; i < wordc; i++){ + if (wordv1[i] == 0 || wordv2[i] == 0) + return(-1); + if (back = strcmp(wordv1[i], wordv2[i])){ + return(back); + } + } + return(0); /* they are equal */ +} + +/* + * splice a 0 basedword vector onto the tail of a + * new wordv, allowing the first emptyhead slots to be empty + */ +char **wordvsplice(emptyhead, wordc, wordv) + int emptyhead; + int wordc; + char **wordv; +{ + reg char **nwordv; + int nwordc = emptyhead + wordc; + reg int i; + + nwordv = (char **)Calloc(nwordc, sizeof (char *)); + for (i = 0; i < emptyhead; i++) + nwordv[i] = 0; + for(i = emptyhead; i < nwordc; i++){ + nwordv[i] = wordv[i-emptyhead]; + } + return(nwordv); +} +/* + * plural'ize and verb forms + */ +static char *S = "s"; +static char *N = ""; +char *plural(n) + int n; +{ + return( n > 1 ? S : N); +} +char *verbform(n) + int n; +{ + return( n > 1 ? N : S); +} + diff --git a/usr.bin/error/touch.c b/usr.bin/error/touch.c new file mode 100644 index 0000000..b4348a1 --- /dev/null +++ b/usr.bin/error/touch.c @@ -0,0 +1,768 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "error.h" +#include "pathnames.h" + +/* + * Iterate through errors + */ +#define EITERATE(p, fv, i) for (p = fv[i]; p < fv[i+1]; p++) +#define ECITERATE(ei, p, lb) for (ei = lb; p = errors[ei],ei < nerrors; ei++) + +#define FILEITERATE(fi, lb) for (fi = lb; fi <= nfiles; fi++) +int touchstatus = Q_YES; + +findfiles(nerrors, errors, r_nfiles, r_files) + int nerrors; + Eptr *errors; + int *r_nfiles; + Eptr ***r_files; +{ + int nfiles; + Eptr **files; + + char *name; + reg int ei; + int fi; + reg Eptr errorp; + + nfiles = countfiles(errors); + + files = (Eptr**)Calloc(nfiles + 3, sizeof (Eptr*)); + touchedfiles = (boolean *)Calloc(nfiles+3, sizeof(boolean)); + /* + * Now, partition off the error messages + * into those that are synchronization, discarded or + * not specific to any file, and those that were + * nulled or true errors. + */ + files[0] = &errors[0]; + ECITERATE(ei, errorp, 0){ + if ( ! (NOTSORTABLE(errorp->error_e_class))) + break; + } + /* + * Now, and partition off all error messages + * for a given file. + */ + files[1] = &errors[ei]; + touchedfiles[0] = touchedfiles[1] = FALSE; + name = "\1"; + fi = 1; + ECITERATE(ei, errorp, ei){ + if ( (errorp->error_e_class == C_NULLED) + || (errorp->error_e_class == C_TRUE) ){ + if (strcmp(errorp->error_text[0], name) != 0){ + name = errorp->error_text[0]; + touchedfiles[fi] = FALSE; + files[fi] = &errors[ei]; + fi++; + } + } + } + files[fi] = &errors[nerrors]; + *r_nfiles = nfiles; + *r_files = files; +} + +int countfiles(errors) + Eptr *errors; +{ + char *name; + int ei; + reg Eptr errorp; + + int nfiles; + nfiles = 0; + name = "\1"; + ECITERATE(ei, errorp, 0){ + if (SORTABLE(errorp->error_e_class)){ + if (strcmp(errorp->error_text[0],name) != 0){ + nfiles++; + name = errorp->error_text[0]; + } + } + } + return(nfiles); +} +char *class_table[] = { + /*C_UNKNOWN 0 */ "Unknown", + /*C_IGNORE 1 */ "ignore", + /*C_SYNC 2 */ "synchronization", + /*C_DISCARD 3 */ "discarded", + /*C_NONSPEC 4 */ "non specific", + /*C_THISFILE 5 */ "specific to this file", + /*C_NULLED 6 */ "nulled", + /*C_TRUE 7 */ "true", + /*C_DUPL 8 */ "duplicated" +}; + +int class_count[C_LAST - C_FIRST] = {0}; + +filenames(nfiles, files) + int nfiles; + Eptr **files; +{ + reg int fi; + char *sep = " "; + extern char *class_table[]; + int someerrors; + + /* + * first, simply dump out errors that + * don't pertain to any file + */ + someerrors = nopertain(files); + + if (nfiles){ + someerrors++; + fprintf(stdout, terse + ? "%d file%s" + : "%d file%s contain%s errors", + nfiles, plural(nfiles), verbform(nfiles)); + if (!terse){ + FILEITERATE(fi, 1){ + fprintf(stdout, "%s\"%s\" (%d)", + sep, (*files[fi])->error_text[0], + files[fi+1] - files[fi]); + sep = ", "; + } + } + fprintf(stdout, "\n"); + } + if (!someerrors) + fprintf(stdout, "No errors.\n"); +} + +/* + * Dump out errors that don't pertain to any file + */ +int nopertain(files) + Eptr **files; +{ + int type; + int someerrors = 0; + reg Eptr *erpp; + reg Eptr errorp; + + if (files[1] - files[0] <= 0) + return(0); + for(type = C_UNKNOWN; NOTSORTABLE(type); type++){ + if (class_count[type] <= 0) + continue; + if (type > C_SYNC) + someerrors++; + if (terse){ + fprintf(stdout, "\t%d %s errors NOT PRINTED\n", + class_count[type], class_table[type]); + } else { + fprintf(stdout, "\n\t%d %s errors follow\n", + class_count[type], class_table[type]); + EITERATE(erpp, files, 0){ + errorp = *erpp; + if (errorp->error_e_class == type){ + errorprint(stdout, errorp, TRUE); + } + } + } + } + return(someerrors); +} + +extern boolean notouch; + +boolean touchfiles(nfiles, files, r_edargc, r_edargv) + int nfiles; + Eptr **files; + int *r_edargc; + char ***r_edargv; +{ + char *name; + reg Eptr errorp; + reg int fi; + reg Eptr *erpp; + int ntrueerrors; + boolean scribbled; + int n_pissed_on; /* # of file touched*/ + int spread; + + FILEITERATE(fi, 1){ + name = (*files[fi])->error_text[0]; + spread = files[fi+1] - files[fi]; + fprintf(stdout, terse + ? "\"%s\" has %d error%s, " + : "\nFile \"%s\" has %d error%s.\n" + , name ,spread ,plural(spread)); + /* + * First, iterate through all error messages in this file + * to see how many of the error messages really will + * get inserted into the file. + */ + ntrueerrors = 0; + EITERATE(erpp, files, fi){ + errorp = *erpp; + if (errorp->error_e_class == C_TRUE) + ntrueerrors++; + } + fprintf(stdout, terse + ? "insert %d\n" + : "\t%d of these errors can be inserted into the file.\n", + ntrueerrors); + + hackfile(name, files, fi, ntrueerrors); + } + scribbled = FALSE; + n_pissed_on = 0; + FILEITERATE(fi, 1){ + scribbled |= touchedfiles[fi]; + n_pissed_on++; + } + if (scribbled){ + /* + * Construct an execv argument + */ + execvarg(n_pissed_on, r_edargc, r_edargv); + return(TRUE); + } else { + if (!terse) + fprintf(stdout, "You didn't touch any files.\n"); + return(FALSE); + } +} + +hackfile(name, files, ix, nerrors) + char *name; + Eptr **files; + int ix; +{ + boolean previewed; + int errordest; /* where errors go*/ + + if (!oktotouch(name)) { + previewed = FALSE; + errordest = TOSTDOUT; + } else { + previewed = preview(name, nerrors, files, ix); + errordest = settotouch(name); + } + + if (errordest != TOSTDOUT) + touchedfiles[ix] = TRUE; + + if (previewed && (errordest == TOSTDOUT)) + return; + + diverterrors(name, errordest, files, ix, previewed, nerrors); + + if (errordest == TOTHEFILE){ + /* + * overwrite the original file + */ + writetouched(1); + } +} + +boolean preview(name, nerrors, files, ix) + char *name; + int nerrors; + Eptr **files; + int ix; +{ + int back; + reg Eptr *erpp; + + if (nerrors <= 0) + return(FALSE); + back = FALSE; + if(query){ + switch(inquire(terse + ? "Preview? " + : "Do you want to preview the errors first? ")){ + case Q_YES: + case Q_yes: + back = TRUE; + EITERATE(erpp, files, ix){ + errorprint(stdout, *erpp, TRUE); + } + if (!terse) + fprintf(stdout, "\n"); + default: + break; + } + } + return(back); +} + +int settotouch(name) + char *name; +{ + int dest = TOSTDOUT; + + if (query){ + switch(touchstatus = inquire(terse + ? "Touch? " + : "Do you want to touch file \"%s\"? ", + name)){ + case Q_NO: + case Q_no: + return(dest); + default: + break; + } + } + + switch(probethisfile(name)){ + case F_NOTREAD: + dest = TOSTDOUT; + fprintf(stdout, terse + ? "\"%s\" unreadable\n" + : "File \"%s\" is unreadable\n", + name); + break; + case F_NOTWRITE: + dest = TOSTDOUT; + fprintf(stdout, terse + ? "\"%s\" unwritable\n" + : "File \"%s\" is unwritable\n", + name); + break; + case F_NOTEXIST: + dest = TOSTDOUT; + fprintf(stdout, terse + ? "\"%s\" not found\n" + : "Can't find file \"%s\" to insert error messages into.\n", + name); + break; + default: + dest = edit(name) ? TOSTDOUT : TOTHEFILE; + break; + } + return(dest); +} + +diverterrors(name, dest, files, ix, previewed, nterrors) + char *name; + int dest; + Eptr **files; + int ix; + boolean previewed; + int nterrors; +{ + int nerrors; + reg Eptr *erpp; + reg Eptr errorp; + + nerrors = files[ix+1] - files[ix]; + + if ( (nerrors != nterrors) + && (!previewed) ){ + fprintf(stdout, terse + ? "Uninserted errors\n" + : ">>Uninserted errors for file \"%s\" follow.\n", + name); + } + + EITERATE(erpp, files, ix){ + errorp = *erpp; + if (errorp->error_e_class != C_TRUE){ + if (previewed || touchstatus == Q_NO) + continue; + errorprint(stdout, errorp, TRUE); + continue; + } + switch (dest){ + case TOSTDOUT: + if (previewed || touchstatus == Q_NO) + continue; + errorprint(stdout,errorp, TRUE); + break; + case TOTHEFILE: + insert(errorp->error_line); + text(errorp, FALSE); + break; + } + } +} + +int oktotouch(filename) + char *filename; +{ + extern char *suffixlist; + reg char *src; + reg char *pat; + char *osrc; + + pat = suffixlist; + if (pat == 0) + return(0); + if (*pat == '*') + return(1); + while (*pat++ != '.') + continue; + --pat; /* point to the period */ + + for (src = &filename[strlen(filename)], --src; + (src > filename) && (*src != '.'); --src) + continue; + if (*src != '.') + return(0); + + for (src++, pat++, osrc = src; *src && *pat; src = osrc, pat++){ + for (; *src /* not at end of the source */ + && *pat /* not off end of pattern */ + && *pat != '.' /* not off end of sub pattern */ + && *pat != '*' /* not wild card */ + && *src == *pat; /* and equal... */ + src++, pat++) + continue; + if (*src == 0 && (*pat == 0 || *pat == '.' || *pat == '*')) + return(1); + if (*src != 0 && *pat == '*') + return(1); + while (*pat && *pat != '.') + pat++; + if (! *pat) + return(0); + } + return(0); +} +/* + * Construct an execv argument + * We need 1 argument for the editor's name + * We need 1 argument for the initial search string + * We need n_pissed_on arguments for the file names + * We need 1 argument that is a null for execv. + * The caller fills in the editor's name. + * We fill in the initial search string. + * We fill in the arguments, and the null. + */ +execvarg(n_pissed_on, r_argc, r_argv) + int n_pissed_on; + int *r_argc; + char ***r_argv; +{ + Eptr p; + char *sep; + int fi; + + (*r_argv) = (char **)Calloc(n_pissed_on + 3, sizeof(char *)); + (*r_argc) = n_pissed_on + 2; + (*r_argv)[1] = "+1;/###/"; + n_pissed_on = 2; + if (!terse){ + fprintf(stdout, "You touched file(s):"); + sep = " "; + } + FILEITERATE(fi, 1){ + if (!touchedfiles[fi]) + continue; + p = *(files[fi]); + if (!terse){ + fprintf(stdout,"%s\"%s\"", sep, p->error_text[0]); + sep = ", "; + } + (*r_argv)[n_pissed_on++] = p->error_text[0]; + } + if (!terse) + fprintf(stdout, "\n"); + (*r_argv)[n_pissed_on] = 0; +} + +FILE *o_touchedfile; /* the old file */ +FILE *n_touchedfile; /* the new file */ +char *o_name; +char n_name[64]; +char *canon_name = _PATH_TMP; +int o_lineno; +int n_lineno; +boolean tempfileopen = FALSE; +/* + * open the file; guaranteed to be both readable and writable + * Well, if it isn't, then return TRUE if something failed + */ +boolean edit(name) + char *name; +{ + o_name = name; + if ( (o_touchedfile = fopen(name, "r")) == NULL){ + fprintf(stderr, "%s: Can't open file \"%s\" to touch (read).\n", + processname, name); + return(TRUE); + } + (void)strcpy(n_name, canon_name); + (void)mktemp(n_name); + if ( (n_touchedfile = fopen(n_name, "w")) == NULL){ + fprintf(stderr,"%s: Can't open file \"%s\" to touch (write).\n", + processname, name); + return(TRUE); + } + tempfileopen = TRUE; + n_lineno = 0; + o_lineno = 0; + return(FALSE); +} +/* + * Position to the line (before, after) the line given by place + */ +char edbuf[BUFSIZ]; +insert(place) + int place; +{ + --place; /* always insert messages before the offending line*/ + for(; o_lineno < place; o_lineno++, n_lineno++){ + if(fgets(edbuf, BUFSIZ, o_touchedfile) == NULL) + return; + fputs(edbuf, n_touchedfile); + } +} + +text(p, use_all) + reg Eptr p; + boolean use_all; +{ + int offset = use_all ? 0 : 2; + + fputs(lang_table[p->error_language].lang_incomment, n_touchedfile); + fprintf(n_touchedfile, "%d [%s] ", + p->error_line, + lang_table[p->error_language].lang_name); + wordvprint(n_touchedfile, p->error_lgtext-offset, p->error_text+offset); + fputs(lang_table[p->error_language].lang_outcomment,n_touchedfile); + n_lineno++; +} + +/* + * write the touched file to its temporary copy, + * then bring the temporary in over the local file + */ +writetouched(overwrite) + int overwrite; +{ + reg int nread; + reg FILE *localfile; + reg FILE *tmpfile; + int botch; + int oktorm; + + botch = 0; + oktorm = 1; + while((nread = fread(edbuf, 1, sizeof(edbuf), o_touchedfile)) != NULL){ + if (nread != fwrite(edbuf, 1, nread, n_touchedfile)){ + /* + * Catastrophe in temporary area: file system full? + */ + botch = 1; + fprintf(stderr, + "%s: write failure: No errors inserted in \"%s\"\n", + processname, o_name); + } + } + fclose(n_touchedfile); + fclose(o_touchedfile); + /* + * Now, copy the temp file back over the original + * file, thus preserving links, etc + */ + if (botch == 0 && overwrite){ + botch = 0; + localfile = NULL; + tmpfile = NULL; + if ((localfile = fopen(o_name, "w")) == NULL){ + fprintf(stderr, + "%s: Can't open file \"%s\" to overwrite.\n", + processname, o_name); + botch++; + } + if ((tmpfile = fopen(n_name, "r")) == NULL){ + fprintf(stderr, "%s: Can't open file \"%s\" to read.\n", + processname, n_name); + botch++; + } + if (!botch) + oktorm = mustoverwrite(localfile, tmpfile); + if (localfile != NULL) + fclose(localfile); + if (tmpfile != NULL) + fclose(tmpfile); + } + if (oktorm == 0){ + fprintf(stderr, "%s: Catastrophe: A copy of \"%s\": was saved in \"%s\"\n", + processname, o_name, n_name); + exit(1); + } + /* + * Kiss the temp file good bye + */ + unlink(n_name); + tempfileopen = FALSE; + return(TRUE); +} +/* + * return 1 if the tmpfile can be removed after writing it out + */ +int mustoverwrite(preciousfile, tmpfile) + FILE *preciousfile; + FILE *tmpfile; +{ + int nread; + + while((nread = fread(edbuf, 1, sizeof(edbuf), tmpfile)) != NULL){ + if (mustwrite(edbuf, nread, preciousfile) == 0) + return(0); + } + return(1); +} +/* + * return 0 on catastrophe + */ +mustwrite(base, n, preciousfile) + char *base; + int n; + FILE *preciousfile; +{ + int nwrote; + + if (n <= 0) + return(1); + nwrote = fwrite(base, 1, n, preciousfile); + if (nwrote == n) + return(1); + perror(processname); + switch(inquire(terse + ? "Botch overwriting: retry? " + : "Botch overwriting the source file: retry? ")){ + case Q_YES: + case Q_yes: + mustwrite(base + nwrote, n - nwrote, preciousfile); + return(1); + case Q_NO: + case Q_no: + switch(inquire("Are you sure? ")){ + case Q_YES: + case Q_yes: + return(0); + case Q_NO: + case Q_no: + mustwrite(base + nwrote, n - nwrote, preciousfile); + return(1); + } + default: + return(0); + } +} + +void +onintr() +{ + switch(inquire(terse + ? "\nContinue? " + : "\nInterrupt: Do you want to continue? ")){ + case Q_YES: + case Q_yes: + signal(SIGINT, onintr); + return; + default: + if (tempfileopen){ + /* + * Don't overwrite the original file! + */ + writetouched(0); + } + exit(1); + } + /*NOTREACHED*/ +} + +errorprint(place, errorp, print_all) + FILE *place; + Eptr errorp; + boolean print_all; +{ + int offset = print_all ? 0 : 2; + + if (errorp->error_e_class == C_IGNORE) + return; + fprintf(place, "[%s] ", lang_table[errorp->error_language].lang_name); + wordvprint(place,errorp->error_lgtext-offset,errorp->error_text+offset); + putc('\n', place); +} + +int inquire(fmt, a1, a2) + char *fmt; + /*VARARGS1*/ +{ + char buffer[128]; + + if (queryfile == NULL) + return(0); + for(;;){ + do{ + fflush(stdout); + fprintf(stderr, fmt, a1, a2); + fflush(stderr); + } while (fgets(buffer, 127, queryfile) == NULL); + switch(buffer[0]){ + case 'Y': return(Q_YES); + case 'y': return(Q_yes); + case 'N': return(Q_NO); + case 'n': return(Q_no); + default: fprintf(stderr, "Yes or No only!\n"); + } + } +} + +int probethisfile(name) + char *name; +{ + struct stat statbuf; + if (stat(name, &statbuf) < 0) + return(F_NOTEXIST); + if((statbuf.st_mode & S_IREAD) == 0) + return(F_NOTREAD); + if((statbuf.st_mode & S_IWRITE) == 0) + return(F_NOTWRITE); + return(F_TOUCHIT); +} diff --git a/usr.bin/expand/Makefile b/usr.bin/expand/Makefile new file mode 100644 index 0000000..751df25 --- /dev/null +++ b/usr.bin/expand/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= expand +MLINKS= expand.1 unexpand.1 + +.include diff --git a/usr.bin/expand/expand.1 b/usr.bin/expand/expand.1 new file mode 100644 index 0000000..e345065 --- /dev/null +++ b/usr.bin/expand/expand.1 @@ -0,0 +1,87 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)expand.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt EXPAND 1 +.Os BSD 4 +.Sh NAME +.Nm expand , +.Nm unexpand +.Nd expand tabs to spaces, and vice versa +.Sh SYNOPSIS +.Nm expand +.Op Fl Ns Ar tabstop +.Op Fl Ns Ar tab1,tab2,...,tabn +.Ar +.Nm unexpand +.Op Fl a +.Ar +.Sh DESCRIPTION +.Nm Expand +processes the named files or the standard input writing +the standard output with tabs changed into blanks. +Backspace characters are preserved into the output and decrement +the column count for tab calculations. +.Nm Expand +is useful for pre-processing character files +(before sorting, looking at specific columns, etc.) that +contain tabs. +.Pp +If a single +.Ar tabstop +argument is given, then tabs are set +.Ar tabstop +spaces apart instead of the default 8. +If multiple tabstops are given then the tabs are set at those +specific columns. +.Pp +.Nm Unexpand +puts tabs back into the data from the standard input or the named +files and writes the result on the standard output. +.Pp +Option (with +.Nm unexpand +only): +.Bl -tag -width flag +.It Fl a +By default, only leading blanks and tabs +are reconverted to maximal strings of tabs. If the +.Fl a +option is given, then tabs are inserted whenever they would compress the +resultant file by replacing two or more characters. +.El +.Sh HISTORY +The +.Nm expand +command appeared in +.Bx 3.0 . diff --git a/usr.bin/expand/expand.c b/usr.bin/expand/expand.c new file mode 100644 index 0000000..c3a00e7 --- /dev/null +++ b/usr.bin/expand/expand.c @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +/* + * expand - expand tabs to equivalent spaces + */ +int nstops; +int tabstops[100]; + +main(argc, argv) + int argc; + char *argv[]; +{ + register int c, column; + register int n; + + argc--, argv++; + do { + while (argc > 0 && argv[0][0] == '-') { + getstops(argv[0]); + argc--, argv++; + } + if (argc > 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + perror(argv[0]); + exit(1); + } + argc--, argv++; + } + column = 0; + for (;;) { + c = getc(stdin); + if (c == -1) + break; + switch (c) { + + case '\t': + if (nstops == 0) { + do { + putchar(' '); + column++; + } while (column & 07); + continue; + } + if (nstops == 1) { + do { + putchar(' '); + column++; + } while (((column - 1) % tabstops[0]) != (tabstops[0] - 1)); + continue; + } + for (n = 0; n < nstops; n++) + if (tabstops[n] > column) + break; + if (n == nstops) { + putchar(' '); + column++; + continue; + } + while (column < tabstops[n]) { + putchar(' '); + column++; + } + continue; + + case '\b': + if (column) + column--; + putchar('\b'); + continue; + + default: + putchar(c); + column++; + continue; + + case '\n': + putchar(c); + column = 0; + continue; + } + } + } while (argc > 0); + exit(0); +} + +getstops(cp) + register char *cp; +{ + register int i; + + nstops = 0; + cp++; + for (;;) { + i = 0; + while (*cp >= '0' && *cp <= '9') + i = i * 10 + *cp++ - '0'; + if (i <= 0 || i > 256) { +bad: + fprintf(stderr, "Bad tab stop spec\n"); + exit(1); + } + if (nstops > 0 && i <= tabstops[nstops-1]) + goto bad; + tabstops[nstops++] = i; + if (*cp == 0) + break; + if (*cp++ != ',') + goto bad; + } +} diff --git a/usr.bin/false/Makefile b/usr.bin/false/Makefile new file mode 100644 index 0000000..ed511ab --- /dev/null +++ b/usr.bin/false/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= false + +.include diff --git a/usr.bin/false/false.1 b/usr.bin/false/false.1 new file mode 100644 index 0000000..bf9a9eb --- /dev/null +++ b/usr.bin/false/false.1 @@ -0,0 +1,63 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)false.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt FALSE 1 +.Os BSD 4.2 +.Sh NAME +.Nm false +.Nd return false value +.Sh SYNOPSIS +.Nm false +.Sh DESCRIPTION +.Nm False +is usually used in a Bourne shell script. +It tests for the appropriate status "false" before running +(or failing to run) a list of commands. +.Pp +The +.Nm false +utility always exits with a value other than zero. +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr true 1 +.Sh STANDARDS +The +.Nm false +utility is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/false/false.c b/usr.bin/false/false.c new file mode 100644 index 0000000..3bb8c00 --- /dev/null +++ b/usr.bin/false/false.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)false.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +main() +{ + exit(1); +} diff --git a/usr.bin/find/Makefile b/usr.bin/find/Makefile new file mode 100644 index 0000000..c305d6a --- /dev/null +++ b/usr.bin/find/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= find +SRCS= find.c function.c ls.c main.c misc.c operator.c option.c + +.include diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h new file mode 100644 index 0000000..3db2d5f --- /dev/null +++ b/usr.bin/find/extern.h @@ -0,0 +1,78 @@ +/*- + * 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. + * + * @(#)extern.h 8.3 (Berkeley) 4/16/94 + */ + +#include + +void brace_subst __P((char *, char **, char *, int)); +void *emalloc __P((unsigned int)); +PLAN *find_create __P((char ***)); +int find_execute __P((PLAN *, char **)); +PLAN *find_formplan __P((char **)); +PLAN *not_squish __P((PLAN *)); +PLAN *or_squish __P((PLAN *)); +PLAN *paren_squish __P((PLAN *)); +struct stat; +void printlong __P((char *, char *, struct stat *)); +int queryuser __P((char **)); + +PLAN *c_atime __P((char *)); +PLAN *c_ctime __P((char *)); +PLAN *c_depth __P((void)); +PLAN *c_exec __P((char ***, int)); +PLAN *c_follow __P((void)); +PLAN *c_fstype __P((char *)); +PLAN *c_group __P((char *)); +PLAN *c_inum __P((char *)); +PLAN *c_links __P((char *)); +PLAN *c_ls __P((void)); +PLAN *c_name __P((char *)); +PLAN *c_newer __P((char *)); +PLAN *c_nogroup __P((void)); +PLAN *c_nouser __P((void)); +PLAN *c_path __P((char *)); +PLAN *c_perm __P((char *)); +PLAN *c_print __P((void)); +PLAN *c_prune __P((void)); +PLAN *c_size __P((char *)); +PLAN *c_type __P((char *)); +PLAN *c_user __P((char *)); +PLAN *c_xdev __P((void)); +PLAN *c_openparen __P((void)); +PLAN *c_closeparen __P((void)); +PLAN *c_mtime __P((char *)); +PLAN *c_not __P((void)); +PLAN *c_or __P((void)); + +extern int ftsoptions, isdeprecated, isdepth, isoutput, isxargs; diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1 new file mode 100644 index 0000000..6523bba --- /dev/null +++ b/usr.bin/find/find.1 @@ -0,0 +1,454 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)find.1 8.4 (Berkeley) 4/1/94 +.\" +.Dd April 1, 1994 +.Dt FIND 1 +.Os +.Sh NAME +.Nm find +.Nd walk a file hierarchy +.Sh SYNOPSIS +.Nm find +.Op Fl H | Fl L | Fl P +.Op Fl Xdx +.Op Fl f Ar file +.Op Ar file ... +.Ar expression +.Sh DESCRIPTION +.Nm Find +recursively descends the directory tree for each +.Ar file +listed, evaluating an +.Ar expression +(composed of the ``primaries'' and ``operands'' listed below) in terms +of each file in the tree. +.Pp +The options are as follows: +.Pp +.Bl -tag -width Ds +.It Fl H +The +.Fl H +option causes the file information and file type (see +.Xr stat 2) +returned for each symbolic link specified on the command line to be +those of the file referenced by the link, not the link itself. +If the referenced file does not exist, the file information and type will +be for the link itself. File information of all symbolic links not on +the command line is that of the link itself. +.It Fl L +The +.Fl L +option causes the file information and file type (see +.Xr stat 2) +returned for each symbolic link to be those of the file referenced by the +link, not the link itself. +If the referenced file does not exist, the file information and type will +be for the link itself. +.It Fl P +The +.Fl P +option causes the file information and file type (see +.Xr stat 2) +returned for each symbolic link to be those of the link itself. +.It Fl X +The +.Fl X +option is a modification to permit +.Nm +to be safely used in conjunction with +.Xr xargs 1 . +If a file name contains any of the delimiting characters used by +.Xr xargs , +a diagnostic message is displayed on standard error, and the file +is skipped. +The delimiting characters include single (`` ' '') and double (`` " '') +quotes, backslash (``\e''), space, tab and newline characters. +.It Fl d +The +.Fl d +option causes +.Nm find +to perform a depth\-first traversal, i.e. directories +are visited in post\-order and all entries in a directory will be acted +on before the directory itself. +By default, +.Nm find +visits directories in pre\-order, i.e. before their contents. +Note, the default is +.Ar not +a breadth\-first traversal. +.It Fl f +The +.Fl f +option specifies a file hierarchy for +.Nm find +to traverse. +File hierarchies may also be specified as the operands immediately +following the options. +.It Fl x +The +.Fl x +option prevents +.Nm find +from descending into directories that have a device number different +than that of the file from which the descent began. +.El +.Sh PRIMARIES +.Bl -tag -width Ds +.It Ic -atime Ar n +True if the difference between the file last access time and the time +.Nm find +was started, rounded up to the next full 24\-hour period, is +.Ar n +24\-hour periods. +.It Ic -ctime Ar n +True if the difference between the time of last change of file status +information and the time +.Nm find +was started, rounded up to the next full 24\-hour period, is +.Ar n +24\-hour periods. +.It Ic -exec Ar utility Op argument ... ; +True if the program named +.Ar utility +returns a zero value as its exit status. +Optional arguments may be passed to the utility. +The expression must be terminated by a semicolon (``;''). +If the string ``{}'' appears anywhere in the utility name or the +arguments it is replaced by the pathname of the current file. +.Ar Utility +will be executed from the directory from which +.Nm find +was executed. +.It Ic -fstype Ar type +True if the file is contained in a file system of type +.Ar type . +Currently supported types are ``local'', ``mfs'', ``nfs'', ``msdos'', +``rdonly'' and ``ufs''. +The types ``local'' and ``rdonly'' are not specific file system types. +The former matches any file system physically mounted on the system where +the +.Nm find +is being executed and the latter matches any file system which is +mounted read-only. +.It Ic -group Ar gname +True if the file belongs to the group +.Ar gname . +If +.Ar gname +is numeric and there is no such group name, then +.Ar gname +is treated as a group id. +.It Ic -inum Ar n +True if the file has inode number +.Ar n . +.It Ic -links Ar n +True if the file has +.Ar n +links. +.It Ic -ls +This primary always evaluates to true. +The following information for the current file is written to standard output: +its inode number, size in 512\-byte blocks, file permissions, number of hard +links, owner, group, size in bytes, last modification time, and pathname. +If the file is a block or character special file, the major and minor numbers +will be displayed instead of the size in bytes. +If the file is a symbolic link, the pathname of the linked\-to file will be +displayed preceded by ``\->''. +The format is identical to that produced by ``ls \-dgils''. +.It Ic -mtime Ar n +True if the difference between the file last modification time and the time +.Nm find +was started, rounded up to the next full 24\-hour period, is +.Ar n +24\-hour periods. +.It Ic \&-ok Ar utility Ns Op argument ... ; +The +.Ic \&-ok +primary is identical to the +.Ic -exec +primary with the exception that +.Nm find +requests user affirmation for the execution of the utility by printing +a message to the terminal and reading a response. +If the response is other than ``y'' the command is not executed and the +value of the +.Ar \&ok +expression is false. +.It Ic -name Ar pattern +True if the last component of the pathname being examined matches +.Ar pattern . +Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'') +may be used as part of +.Ar pattern . +These characters may be matched explicitly by escaping them with a +backslash (``\e''). +.It Ic -newer Ar file +True if the current file has a more recent last modification time than +.Ar file . +.It Ic -nouser +True if the file belongs to an unknown user. +.It Ic -nogroup +True if the file belongs to an unknown group. +.It Ic -path Ar pattern +True if the pathname being examined matches +.Ar pattern . +Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'') +may be used as part of +.Ar pattern . +These characters may be matched explicitly by escaping them with a +backslash (``\e''). +Slashes (``/'') are treated as normal characters and do not have to be +matched explicitly. +.It Ic -perm Op Fl Ns Ar mode +The +.Ar mode +may be either symbolic (see +.Xr chmod 1 ) +or an octal number. +If the mode is symbolic, a starting value of zero is assumed and the +mode sets or clears permissions without regard to the process' file mode +creation mask. +If the mode is octal, only bits 07777 +.Pf ( Dv S_ISUID +| +.Dv S_ISGID +| +.Dv S_ISTXT +| +.Dv S_IRWXU +| +.Dv S_IRWXG +| +.Dv S_IRWXO ) +of the file's mode bits participate +in the comparison. +If the mode is preceded by a dash (``\-''), this primary evaluates to true +if at least all of the bits in the mode are set in the file's mode bits. +If the mode is not preceded by a dash, this primary evaluates to true if +the bits in the mode exactly match the file's mode bits. +Note, the first character of a symbolic mode may not be a dash (``\-''). +.It Ic -print +This primary always evaluates to true. +It prints the pathname of the current file to standard output. +The expression is appended to the user specified expression if neither +.Ic -exec , +.Ic -ls +or +.Ic \&-ok +is specified. +.It Ic -prune +This primary always evaluates to true. +It causes +.Nm find +to not descend into the current file. +Note, the +.Ic -prune +primary has no effect if the +.Fl d +option was specified. +.It Ic -size Ar n Ns Op Cm c +True if the file's size, rounded up, in 512\-byte blocks is +.Ar n . +If +.Ar n +is followed by a ``c'', then the primary is true if the +file's size is +.Ar n +bytes. +.It Ic -type Ar t +True if the file is of the specified type. +Possible file types are as follows: +.Pp +.Bl -tag -width flag -offset indent -compact +.It Cm b +block special +.It Cm c +character special +.It Cm d +directory +.It Cm f +regular file +.It Cm l +symbolic link +.It Cm p +FIFO +.It Cm s +socket +.El +.Pp +.It Ic -user Ar uname +True if the file belongs to the user +.Ar uname . +If +.Ar uname +is numeric and there is no such user name, then +.Ar uname +is treated as a user id. +.El +.Pp +All primaries which take a numeric argument allow the number to be +preceded by a plus sign (``+'') or a minus sign (``\-''). +A preceding plus sign means ``more than n'', a preceding minus sign means +``less than n'' and neither means ``exactly n'' . +.Sh OPERATORS +The primaries may be combined using the following operators. +The operators are listed in order of decreasing precedence. +.Bl -tag -width (expression) +.It Cm \&( Ns Ar expression Ns Cm \&) +This evaluates to true if the parenthesized expression evaluates to +true. +.Pp +.It Cm \&! Ns Ar expression +This is the unary +.Tn NOT +operator. +It evaluates to true if the expression is false. +.Pp +.It Ar expression Cm -and Ar expression +.It Ar expression expression +The +.Cm -and +operator is the logical +.Tn AND +operator. +As it is implied by the juxtaposition of two expressions it does not +have to be specified. +The expression evaluates to true if both expressions are true. +The second expression is not evaluated if the first expression is false. +.Pp +.It Ar expression Cm -or Ar expression +The +.Cm -or +operator is the logical +.Tn OR +operator. +The expression evaluates to true if either the first or the second expression +is true. +The second expression is not evaluated if the first expression is true. +.El +.Pp +All operands and primaries must be separate arguments to +.Nm find . +Primaries which themselves take arguments expect each argument +to be a separate argument to +.Nm find . +.Sh EXAMPLES +.Pp +The following examples are shown as given to the shell: +.Bl -tag -width findx +.It Li "find / \e! -name \*q*.c\*q -print" +Print out a list of all the files whose names do not end in ``.c''. +.It Li "find / -newer ttt -user wnj -print" +Print out a list of all the files owned by user ``wnj'' that are newer +than the file ``ttt''. +.It Li "find / \e! \e( -newer ttt -user wnj \e) -print" +Print out a list of all the files which are not both newer than ``ttt'' +and owned by ``wnj''. +.It Li "find / \e( -newer ttt -or -user wnj \e) -print" +Print out a list of all the files that are either owned by ``wnj'' or +that are newer than ``ttt''. +.El +.Sh SEE ALSO +.Xr chmod 1 , +.Xr locate 1 , +.Xr stat 2 , +.Xr fts 3 , +.Xr getgrent 3 , +.Xr getpwent 3 , +.Xr strmode 3 , +.Xr symlink 7 +.Sh STANDARDS +The +.Nm find +utility syntax is a superset of the syntax specified by the +.St -p1003.2 +standard. +.Pp +The +.Fl s +and +.Fl X +options and the +.Ic -inum +and +.Ic -ls +primaries are extensions to +.St -p1003.2 . +.Pp +Historically, the +.Fl d , +.Fl h +and +.Fl x +options were implemented using the primaries ``\-depth'', ``\-follow'', +and ``\-xdev''. +These primaries always evaluated to true. +As they were really global variables that took effect before the traversal +began, some legal expressions could have unexpected results. +An example is the expression ``\-print \-o \-depth''. +As \-print always evaluates to true, the standard order of evaluation +implies that \-depth would never be evaluated. +This is not the case. +.Pp +The operator ``-or'' was implemented as ``\-o'', and the operator ``-and'' +was implemented as ``\-a''. +.Pp +Historic implementations of the +.Ic exec +and +.Ic ok +primaries did not replace the string ``{}'' in the utility name or the +utility arguments if it had preceding or following non-whitespace characters. +This version replaces it no matter where in the utility name or arguments +it appears. +.Sh BUGS +The special characters used by +.Nm find +are also special characters to many shell programs. +In particular, the characters ``*'', ``['', ``]'', ``?'', ``('', ``)'', +``!'', ``\e'' and ``;'' may have to be escaped from the shell. +.Pp +As there is no delimiter separating options and file names or file +names and the +.Ar expression , +it is difficult to specify files named ``-xdev'' or ``!''. +These problems are handled by the +.Fl f +option and the +.Xr getopt 3 +``--'' construct. diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c new file mode 100644 index 0000000..22fc3a3 --- /dev/null +++ b/usr.bin/find/find.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)find.c 8.3 (Berkeley) 4/1/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "find.h" + +/* + * find_formplan -- + * process the command line and create a "plan" corresponding to the + * command arguments. + */ +PLAN * +find_formplan(argv) + char **argv; +{ + PLAN *plan, *tail, *new; + + /* + * for each argument in the command line, determine what kind of node + * it is, create the appropriate node type and add the new plan node + * to the end of the existing plan. The resulting plan is a linked + * list of plan nodes. For example, the string: + * + * % find . -name foo -newer bar -print + * + * results in the plan: + * + * [-name foo]--> [-newer bar]--> [-print] + * + * in this diagram, `[-name foo]' represents the plan node generated + * by c_name() with an argument of foo and `-->' represents the + * plan->next pointer. + */ + for (plan = tail = NULL; *argv;) { + if (!(new = find_create(&argv))) + continue; + if (plan == NULL) + tail = plan = new; + else { + tail->next = new; + tail = new; + } + } + + /* + * if the user didn't specify one of -print, -ok or -exec, then -print + * is assumed so we add a -print node on the end. It is possible that + * the user might want the -print someplace else on the command line, + * but there's no way to know that. + */ + if (!isoutput) { + new = c_print(); + if (plan == NULL) + tail = plan = new; + else { + tail->next = new; + tail = new; + } + } + + /* + * the command line has been completely processed into a search plan + * except for the (, ), !, and -o operators. Rearrange the plan so + * that the portions of the plan which are affected by the operators + * are moved into operator nodes themselves. For example: + * + * [!]--> [-name foo]--> [-print] + * + * becomes + * + * [! [-name foo] ]--> [-print] + * + * and + * + * [(]--> [-depth]--> [-name foo]--> [)]--> [-print] + * + * becomes + * + * [expr [-depth]-->[-name foo] ]--> [-print] + * + * operators are handled in order of precedence. + */ + + plan = paren_squish(plan); /* ()'s */ + plan = not_squish(plan); /* !'s */ + plan = or_squish(plan); /* -o's */ + return (plan); +} + +FTS *tree; /* pointer to top of FTS hierarchy */ + +/* + * find_execute -- + * take a search plan and an array of search paths and executes the plan + * over all FTSENT's returned for the given search paths. + */ +int +find_execute(plan, paths) + PLAN *plan; /* search plan */ + char **paths; /* array of pathnames to traverse */ +{ + register FTSENT *entry; + PLAN *p; + int rval; + + if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL) + err(1, "ftsopen"); + + for (rval = 0; (entry = fts_read(tree)) != NULL;) { + switch (entry->fts_info) { + case FTS_D: + if (isdepth) + continue; + break; + case FTS_DP: + if (!isdepth) + continue; + break; + case FTS_DNR: + case FTS_ERR: + case FTS_NS: + (void)fflush(stdout); + warnx("%s: %s", + entry->fts_path, strerror(entry->fts_errno)); + rval = 1; + continue; + } +#define BADCH " \t\n\\'\"" + if (isxargs && strpbrk(entry->fts_path, BADCH)) { + (void)fflush(stdout); + warnx("%s: illegal path", entry->fts_path); + rval = 1; + continue; + } + + /* + * Call all the functions in the execution plan until one is + * false or all have been executed. This is where we do all + * the work specified by the user on the command line. + */ + for (p = plan; p && (p->eval)(p, entry); p = p->next); + } + if (errno) + err(1, "fts_read"); + return (rval); +} diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h new file mode 100644 index 0000000..4c4ffa5 --- /dev/null +++ b/usr.bin/find/find.h @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)find.h 8.1 (Berkeley) 6/6/93 + */ + +/* node type */ +enum ntype { + N_AND = 1, /* must start > 0 */ + N_ATIME, N_CLOSEPAREN, N_CTIME, N_DEPTH, N_EXEC, N_EXPR, N_FOLLOW, + N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, N_MTIME, N_NAME, N_NEWER, + N_NOGROUP, N_NOT, N_NOUSER, N_OK, N_OPENPAREN, N_OR, N_PATH, + N_PERM, N_PRINT, N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV, +}; + +/* node definition */ +typedef struct _plandata { + struct _plandata *next; /* next node */ + int (*eval) /* node evaluation function */ + __P((struct _plandata *, FTSENT *)); +#define F_EQUAL 1 /* [acm]time inum links size */ +#define F_LESSTHAN 2 +#define F_GREATER 3 +#define F_NEEDOK 1 /* exec ok */ +#define F_MTFLAG 1 /* fstype */ +#define F_MTTYPE 2 +#define F_ATLEAST 1 /* perm */ + int flags; /* private flags */ + enum ntype type; /* plan node type */ + union { + gid_t _g_data; /* gid */ + ino_t _i_data; /* inode */ + mode_t _m_data; /* mode mask */ + nlink_t _l_data; /* link count */ + off_t _o_data; /* file size */ + time_t _t_data; /* time value */ + uid_t _u_data; /* uid */ + short _mt_data; /* mount flags */ + struct _plandata *_p_data[2]; /* PLAN trees */ + struct _ex { + char **_e_argv; /* argv array */ + char **_e_orig; /* original strings */ + int *_e_len; /* allocated length */ + } ex; + char *_a_data[2]; /* array of char pointers */ + char *_c_data; /* char pointer */ + } p_un; +} PLAN; +#define a_data p_un._a_data +#define c_data p_un._c_data +#define i_data p_un._i_data +#define g_data p_un._g_data +#define l_data p_un._l_data +#define m_data p_un._m_data +#define mt_data p_un._mt_data +#define o_data p_un._o_data +#define p_data p_un._p_data +#define t_data p_un._t_data +#define u_data p_un._u_data +#define e_argv p_un.ex._e_argv +#define e_orig p_un.ex._e_orig +#define e_len p_un.ex._e_len + +typedef struct _option { + char *name; /* option name */ + enum ntype token; /* token type */ + PLAN *(*create)(); /* create function: DON'T PROTOTYPE! */ +#define O_NONE 0x01 /* no call required */ +#define O_ZERO 0x02 /* pass: nothing */ +#define O_ARGV 0x04 /* pass: argv, increment argv */ +#define O_ARGVP 0x08 /* pass: *argv, N_OK || N_EXEC */ + int flags; +} OPTION; + +#include "extern.h" diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c new file mode 100644 index 0000000..f537676 --- /dev/null +++ b/usr.bin/find/function.c @@ -0,0 +1,1069 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)function.c 8.6 (Berkeley) 4/1/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "find.h" + +#define COMPARE(a, b) { \ + switch (plan->flags) { \ + case F_EQUAL: \ + return (a == b); \ + case F_LESSTHAN: \ + return (a < b); \ + case F_GREATER: \ + return (a > b); \ + default: \ + abort(); \ + } \ +} + +static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *)))); + +/* + * find_parsenum -- + * Parse a string of the form [+-]# and return the value. + */ +static long +find_parsenum(plan, option, vp, endch) + PLAN *plan; + char *option, *vp, *endch; +{ + long value; + char *endchar, *str; /* Pointer to character ending conversion. */ + + /* Determine comparison from leading + or -. */ + str = vp; + switch (*str) { + case '+': + ++str; + plan->flags = F_GREATER; + break; + case '-': + ++str; + plan->flags = F_LESSTHAN; + break; + default: + plan->flags = F_EQUAL; + break; + } + + /* + * Convert the string with strtol(). Note, if strtol() returns zero + * and endchar points to the beginning of the string we know we have + * a syntax error. + */ + value = strtol(str, &endchar, 10); + if (value == 0 && endchar == str) + errx(1, "%s: %s: illegal numeric value", option, vp); + if (endchar[0] && (endch == NULL || endchar[0] != *endch)) + errx(1, "%s: %s: illegal trailing character", option, vp); + if (endch) + *endch = endchar[0]; + return (value); +} + +/* + * The value of n for the inode times (atime, ctime, and mtime) is a range, + * i.e. n matches from (n - 1) to n 24 hour periods. This interacts with + * -n, such that "-mtime -1" would be less than 0 days, which isn't what the + * user wanted. Correct so that -1 is "less than 1". + */ +#define TIME_CORRECT(p, ttype) \ + if ((p)->type == ttype && (p)->flags == F_LESSTHAN) \ + ++((p)->t_data); + +/* + * -atime n functions -- + * + * True if the difference between the file access time and the + * current time is n 24 hour periods. + */ +int +f_atime(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + extern time_t now; + + COMPARE((now - entry->fts_statp->st_atime + + SECSPERDAY - 1) / SECSPERDAY, plan->t_data); +} + +PLAN * +c_atime(arg) + char *arg; +{ + PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_ATIME, f_atime); + new->t_data = find_parsenum(new, "-atime", arg, NULL); + TIME_CORRECT(new, N_ATIME); + return (new); +} +/* + * -ctime n functions -- + * + * True if the difference between the last change of file + * status information and the current time is n 24 hour periods. + */ +int +f_ctime(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + extern time_t now; + + COMPARE((now - entry->fts_statp->st_ctime + + SECSPERDAY - 1) / SECSPERDAY, plan->t_data); +} + +PLAN * +c_ctime(arg) + char *arg; +{ + PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_CTIME, f_ctime); + new->t_data = find_parsenum(new, "-ctime", arg, NULL); + TIME_CORRECT(new, N_CTIME); + return (new); +} + +/* + * -depth functions -- + * + * Always true, causes descent of the directory hierarchy to be done + * so that all entries in a directory are acted on before the directory + * itself. + */ +int +f_always_true(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (1); +} + +PLAN * +c_depth() +{ + isdepth = 1; + + return (palloc(N_DEPTH, f_always_true)); +} + +/* + * [-exec | -ok] utility [arg ... ] ; functions -- + * + * True if the executed utility returns a zero value as exit status. + * The end of the primary expression is delimited by a semicolon. If + * "{}" occurs anywhere, it gets replaced by the current pathname. + * The current directory for the execution of utility is the same as + * the current directory when the find utility was started. + * + * The primary -ok is different in that it requests affirmation of the + * user before executing the utility. + */ +int +f_exec(plan, entry) + register PLAN *plan; + FTSENT *entry; +{ + extern int dotfd; + register int cnt; + pid_t pid; + int status; + + for (cnt = 0; plan->e_argv[cnt]; ++cnt) + if (plan->e_len[cnt]) + brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt], + entry->fts_path, plan->e_len[cnt]); + + if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv)) + return (0); + + switch (pid = vfork()) { + case -1: + err(1, "fork"); + /* NOTREACHED */ + case 0: + if (fchdir(dotfd)) { + warn("chdir"); + _exit(1); + } + execvp(plan->e_argv[0], plan->e_argv); + warn("%s", plan->e_argv[0]); + _exit(1); + } + pid = waitpid(pid, &status, 0); + return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); +} + +/* + * c_exec -- + * build three parallel arrays, one with pointers to the strings passed + * on the command line, one with (possibly duplicated) pointers to the + * argv array, and one with integer values that are lengths of the + * strings, but also flags meaning that the string has to be massaged. + */ +PLAN * +c_exec(argvp, isok) + char ***argvp; + int isok; +{ + PLAN *new; /* node returned */ + register int cnt; + register char **argv, **ap, *p; + + isoutput = 1; + + new = palloc(N_EXEC, f_exec); + if (isok) + new->flags = F_NEEDOK; + + for (ap = argv = *argvp;; ++ap) { + if (!*ap) + errx(1, + "%s: no terminating \";\"", isok ? "-ok" : "-exec"); + if (**ap == ';') + break; + } + + cnt = ap - *argvp + 1; + new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *)); + new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *)); + new->e_len = (int *)emalloc((u_int)cnt * sizeof(int)); + + for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { + new->e_orig[cnt] = *argv; + for (p = *argv; *p; ++p) + if (p[0] == '{' && p[1] == '}') { + new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN); + new->e_len[cnt] = MAXPATHLEN; + break; + } + if (!*p) { + new->e_argv[cnt] = *argv; + new->e_len[cnt] = 0; + } + } + new->e_argv[cnt] = new->e_orig[cnt] = NULL; + + *argvp = argv + 1; + return (new); +} + +/* + * -follow functions -- + * + * Always true, causes symbolic links to be followed on a global + * basis. + */ +PLAN * +c_follow() +{ + ftsoptions &= ~FTS_PHYSICAL; + ftsoptions |= FTS_LOGICAL; + + return (palloc(N_FOLLOW, f_always_true)); +} + +/* + * -fstype functions -- + * + * True if the file is of a certain type. + */ +int +f_fstype(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + static dev_t curdev; /* need a guaranteed illegal dev value */ + static int first = 1; + struct statfs sb; + static short val; + char *p, save[2]; + + /* Only check when we cross mount point. */ + if (first || curdev != entry->fts_statp->st_dev) { + curdev = entry->fts_statp->st_dev; + + /* + * Statfs follows symlinks; find wants the link's file system, + * not where it points. + */ + if (entry->fts_info == FTS_SL || + entry->fts_info == FTS_SLNONE) { + if ((p = strrchr(entry->fts_accpath, '/')) != NULL) + ++p; + else + p = entry->fts_accpath; + save[0] = p[0]; + p[0] = '.'; + save[1] = p[1]; + p[1] = '\0'; + + } else + p = NULL; + + if (statfs(entry->fts_accpath, &sb)) + err(1, "%s", entry->fts_accpath); + + if (p) { + p[0] = save[0]; + p[1] = save[1]; + } + + first = 0; + switch (plan->flags) { + case F_MTFLAG: + val = sb.f_flags; + break; + case F_MTTYPE: + val = sb.f_type; + break; + default: + abort(); + } + } + switch(plan->flags) { + case F_MTFLAG: + return (val & plan->mt_data); + case F_MTTYPE: + return (val == plan->mt_data); + default: + abort(); + } +} + +PLAN * +c_fstype(arg) + char *arg; +{ + register PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_FSTYPE, f_fstype); + switch (*arg) { + case 'l': + if (!strcmp(arg, "local")) { + new->flags = F_MTFLAG; + new->mt_data = MNT_LOCAL; + return (new); + } + break; + case 'm': + if (!strcmp(arg, "mfs")) { + new->flags = F_MTTYPE; + new->mt_data = MOUNT_MFS; + return (new); + } + break; + case 'n': + if (!strcmp(arg, "nfs")) { + new->flags = F_MTTYPE; + new->mt_data = MOUNT_NFS; + return (new); + } + break; + case 'p': + if (!strcmp(arg, "msdos")) { + new->flags = F_MTTYPE; + new->mt_data = MOUNT_MSDOS; + return (new); + } + break; + case 'r': + if (!strcmp(arg, "rdonly")) { + new->flags = F_MTFLAG; + new->mt_data = MNT_RDONLY; + return (new); + } + break; + case 'u': + if (!strcmp(arg, "ufs")) { + new->flags = F_MTTYPE; + new->mt_data = MOUNT_UFS; + return (new); + } + break; + } + errx(1, "%s: unknown file type", arg); + /* NOTREACHED */ +} + +/* + * -group gname functions -- + * + * True if the file belongs to the group gname. If gname is numeric and + * an equivalent of the getgrnam() function does not return a valid group + * name, gname is taken as a group ID. + */ +int +f_group(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (entry->fts_statp->st_gid == plan->g_data); +} + +PLAN * +c_group(gname) + char *gname; +{ + PLAN *new; + struct group *g; + gid_t gid; + + ftsoptions &= ~FTS_NOSTAT; + + g = getgrnam(gname); + if (g == NULL) { + gid = atoi(gname); + if (gid == 0 && gname[0] != '0') + errx(1, "-group: %s: no such group", gname); + } else + gid = g->gr_gid; + + new = palloc(N_GROUP, f_group); + new->g_data = gid; + return (new); +} + +/* + * -inum n functions -- + * + * True if the file has inode # n. + */ +int +f_inum(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + COMPARE(entry->fts_statp->st_ino, plan->i_data); +} + +PLAN * +c_inum(arg) + char *arg; +{ + PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_INUM, f_inum); + new->i_data = find_parsenum(new, "-inum", arg, NULL); + return (new); +} + +/* + * -links n functions -- + * + * True if the file has n links. + */ +int +f_links(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + COMPARE(entry->fts_statp->st_nlink, plan->l_data); +} + +PLAN * +c_links(arg) + char *arg; +{ + PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_LINKS, f_links); + new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL); + return (new); +} + +/* + * -ls functions -- + * + * Always true - prints the current entry to stdout in "ls" format. + */ +int +f_ls(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp); + return (1); +} + +PLAN * +c_ls() +{ + ftsoptions &= ~FTS_NOSTAT; + isoutput = 1; + + return (palloc(N_LS, f_ls)); +} + +/* + * -mtime n functions -- + * + * True if the difference between the file modification time and the + * current time is n 24 hour periods. + */ +int +f_mtime(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + extern time_t now; + + COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) / + SECSPERDAY, plan->t_data); +} + +PLAN * +c_mtime(arg) + char *arg; +{ + PLAN *new; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_MTIME, f_mtime); + new->t_data = find_parsenum(new, "-mtime", arg, NULL); + TIME_CORRECT(new, N_MTIME); + return (new); +} + +/* + * -name functions -- + * + * True if the basename of the filename being examined + * matches pattern using Pattern Matching Notation S3.14 + */ +int +f_name(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (!fnmatch(plan->c_data, entry->fts_name, 0)); +} + +PLAN * +c_name(pattern) + char *pattern; +{ + PLAN *new; + + new = palloc(N_NAME, f_name); + new->c_data = pattern; + return (new); +} + +/* + * -newer file functions -- + * + * True if the current file has been modified more recently + * then the modification time of the file named by the pathname + * file. + */ +int +f_newer(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (entry->fts_statp->st_mtime > plan->t_data); +} + +PLAN * +c_newer(filename) + char *filename; +{ + PLAN *new; + struct stat sb; + + ftsoptions &= ~FTS_NOSTAT; + + if (stat(filename, &sb)) + err(1, "%s", filename); + new = palloc(N_NEWER, f_newer); + new->t_data = sb.st_mtime; + return (new); +} + +/* + * -nogroup functions -- + * + * True if file belongs to a user ID for which the equivalent + * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. + */ +int +f_nogroup(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + char *group_from_gid(); + + return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1); +} + +PLAN * +c_nogroup() +{ + ftsoptions &= ~FTS_NOSTAT; + + return (palloc(N_NOGROUP, f_nogroup)); +} + +/* + * -nouser functions -- + * + * True if file belongs to a user ID for which the equivalent + * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. + */ +int +f_nouser(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + char *user_from_uid(); + + return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1); +} + +PLAN * +c_nouser() +{ + ftsoptions &= ~FTS_NOSTAT; + + return (palloc(N_NOUSER, f_nouser)); +} + +/* + * -path functions -- + * + * True if the path of the filename being examined + * matches pattern using Pattern Matching Notation S3.14 + */ +int +f_path(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (!fnmatch(plan->c_data, entry->fts_path, 0)); +} + +PLAN * +c_path(pattern) + char *pattern; +{ + PLAN *new; + + new = palloc(N_NAME, f_path); + new->c_data = pattern; + return (new); +} + +/* + * -perm functions -- + * + * The mode argument is used to represent file mode bits. If it starts + * with a leading digit, it's treated as an octal mode, otherwise as a + * symbolic mode. + */ +int +f_perm(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + mode_t mode; + + mode = entry->fts_statp->st_mode & + (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO); + if (plan->flags == F_ATLEAST) + return ((plan->m_data | mode) == mode); + else + return (mode == plan->m_data); + /* NOTREACHED */ +} + +PLAN * +c_perm(perm) + char *perm; +{ + PLAN *new; + mode_t *set; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_PERM, f_perm); + + if (*perm == '-') { + new->flags = F_ATLEAST; + ++perm; + } + + if ((set = setmode(perm)) == NULL) + err(1, "-perm: %s: illegal mode string", perm); + + new->m_data = getmode(set, 0); + return (new); +} + +/* + * -print functions -- + * + * Always true, causes the current pathame to be written to + * standard output. + */ +int +f_print(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + (void)printf("%s\n", entry->fts_path); + return (1); +} + +PLAN * +c_print() +{ + isoutput = 1; + + return (palloc(N_PRINT, f_print)); +} + +/* + * -prune functions -- + * + * Prune a portion of the hierarchy. + */ +int +f_prune(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + extern FTS *tree; + + if (fts_set(tree, entry, FTS_SKIP)) + err(1, "%s", entry->fts_path); + return (1); +} + +PLAN * +c_prune() +{ + return (palloc(N_PRUNE, f_prune)); +} + +/* + * -size n[c] functions -- + * + * True if the file size in bytes, divided by an implementation defined + * value and rounded up to the next integer, is n. If n is followed by + * a c, the size is in bytes. + */ +#define FIND_SIZE 512 +static int divsize = 1; + +int +f_size(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + off_t size; + + size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) / + FIND_SIZE : entry->fts_statp->st_size; + COMPARE(size, plan->o_data); +} + +PLAN * +c_size(arg) + char *arg; +{ + PLAN *new; + char endch; + + ftsoptions &= ~FTS_NOSTAT; + + new = palloc(N_SIZE, f_size); + endch = 'c'; + new->o_data = find_parsenum(new, "-size", arg, &endch); + if (endch == 'c') + divsize = 0; + return (new); +} + +/* + * -type c functions -- + * + * True if the type of the file is c, where c is b, c, d, p, or f for + * block special file, character special file, directory, FIFO, or + * regular file, respectively. + */ +int +f_type(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data); +} + +PLAN * +c_type(typestring) + char *typestring; +{ + PLAN *new; + mode_t mask; + + ftsoptions &= ~FTS_NOSTAT; + + switch (typestring[0]) { + case 'b': + mask = S_IFBLK; + break; + case 'c': + mask = S_IFCHR; + break; + case 'd': + mask = S_IFDIR; + break; + case 'f': + mask = S_IFREG; + break; + case 'l': + mask = S_IFLNK; + break; + case 'p': + mask = S_IFIFO; + break; + case 's': + mask = S_IFSOCK; + break; + default: + errx(1, "-type: %s: unknown type", typestring); + } + + new = palloc(N_TYPE, f_type); + new->m_data = mask; + return (new); +} + +/* + * -user uname functions -- + * + * True if the file belongs to the user uname. If uname is numeric and + * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not + * return a valid user name, uname is taken as a user ID. + */ +int +f_user(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + return (entry->fts_statp->st_uid == plan->u_data); +} + +PLAN * +c_user(username) + char *username; +{ + PLAN *new; + struct passwd *p; + uid_t uid; + + ftsoptions &= ~FTS_NOSTAT; + + p = getpwnam(username); + if (p == NULL) { + uid = atoi(username); + if (uid == 0 && username[0] != '0') + errx(1, "-user: %s: no such user", username); + } else + uid = p->pw_uid; + + new = palloc(N_USER, f_user); + new->u_data = uid; + return (new); +} + +/* + * -xdev functions -- + * + * Always true, causes find not to decend past directories that have a + * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) + */ +PLAN * +c_xdev() +{ + ftsoptions |= FTS_XDEV; + + return (palloc(N_XDEV, f_always_true)); +} + +/* + * ( expression ) functions -- + * + * True if expression is true. + */ +int +f_expr(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + register PLAN *p; + register int state; + + for (p = plan->p_data[0]; + p && (state = (p->eval)(p, entry)); p = p->next); + return (state); +} + +/* + * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are + * eliminated during phase 2 of find_formplan() --- the '(' node is converted + * to a N_EXPR node containing the expression and the ')' node is discarded. + */ +PLAN * +c_openparen() +{ + return (palloc(N_OPENPAREN, (int (*)())-1)); +} + +PLAN * +c_closeparen() +{ + return (palloc(N_CLOSEPAREN, (int (*)())-1)); +} + +/* + * ! expression functions -- + * + * Negation of a primary; the unary NOT operator. + */ +int +f_not(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + register PLAN *p; + register int state; + + for (p = plan->p_data[0]; + p && (state = (p->eval)(p, entry)); p = p->next); + return (!state); +} + +PLAN * +c_not() +{ + return (palloc(N_NOT, f_not)); +} + +/* + * expression -o expression functions -- + * + * Alternation of primaries; the OR operator. The second expression is + * not evaluated if the first expression is true. + */ +int +f_or(plan, entry) + PLAN *plan; + FTSENT *entry; +{ + register PLAN *p; + register int state; + + for (p = plan->p_data[0]; + p && (state = (p->eval)(p, entry)); p = p->next); + + if (state) + return (1); + + for (p = plan->p_data[1]; + p && (state = (p->eval)(p, entry)); p = p->next); + return (state); +} + +PLAN * +c_or() +{ + return (palloc(N_OR, f_or)); +} + +static PLAN * +palloc(t, f) + enum ntype t; + int (*f) __P((PLAN *, FTSENT *)); +{ + PLAN *new; + + if ((new = malloc(sizeof(PLAN))) == NULL) + err(1, NULL); + new->type = t; + new->eval = f; + new->flags = 0; + new->next = NULL; + return (new); +} diff --git a/usr.bin/find/ls.c b/usr.bin/find/ls.c new file mode 100644 index 0000000..dd51f97 --- /dev/null +++ b/usr.bin/find/ls.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Derived from the print routines in the ls(1) source code. */ + +static void printlink __P((char *)); +static void printtime __P((time_t)); + +void +printlong(name, accpath, sb) + char *name; /* filename to print */ + char *accpath; /* current valid path to filename */ + struct stat *sb; /* stat buffer */ +{ + char modep[15], *user_from_uid(), *group_from_gid(); + + (void)printf("%6lu %4qd ", sb->st_ino, sb->st_blocks); + (void)strmode(sb->st_mode, modep); + (void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, UT_NAMESIZE, + user_from_uid(sb->st_uid, 0), UT_NAMESIZE, + group_from_gid(sb->st_gid, 0)); + + if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode)) + (void)printf("%3d, %3d ", major(sb->st_rdev), + minor(sb->st_rdev)); + else + (void)printf("%8qd ", sb->st_size); + printtime(sb->st_mtime); + (void)printf("%s", name); + if (S_ISLNK(sb->st_mode)) + printlink(accpath); + (void)putchar('\n'); +} + +static void +printtime(ftime) + time_t ftime; +{ + int i; + char *longstring, *ctime(); + time_t time(); + + longstring = ctime((long *)&ftime); + for (i = 4; i < 11; ++i) + (void)putchar(longstring[i]); + +#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) + if (ftime + SIXMONTHS > time((time_t *)NULL)) + for (i = 11; i < 16; ++i) + (void)putchar(longstring[i]); + else { + (void)putchar(' '); + for (i = 20; i < 24; ++i) + (void)putchar(longstring[i]); + } + (void)putchar(' '); +} + +static void +printlink(name) + char *name; +{ + int lnklen; + char path[MAXPATHLEN + 1]; + + if ((lnklen = readlink(name, path, MAXPATHLEN)) == -1) { + warn("%s", name); + return; + } + path[lnklen] = '\0'; + (void)printf(" -> %s", path); +} diff --git a/usr.bin/find/main.c b/usr.bin/find/main.c new file mode 100644 index 0000000..c8375863 --- /dev/null +++ b/usr.bin/find/main.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "find.h" + +time_t now; /* time find was run */ +int dotfd; /* starting directory */ +int ftsoptions; /* options for the ftsopen(3) call */ +int isdeprecated; /* using deprecated syntax */ +int isdepth; /* do directories on post-order visit */ +int isoutput; /* user specified output operator */ +int isxargs; /* don't permit xargs delimiting chars */ + +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char **p, **start; + int Hflag, Lflag, Pflag, ch; + + (void)time(&now); /* initialize the time-of-day */ + + p = start = argv; + Hflag = Lflag = Pflag = 0; + ftsoptions = FTS_NOSTAT | FTS_PHYSICAL; + while ((ch = getopt(argc, argv, "HLPXdf:x")) != EOF) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; + case 'X': + isxargs = 1; + break; + case 'd': + isdepth = 1; + break; + case 'f': + *p++ = optarg; + break; + case 'x': + ftsoptions |= FTS_XDEV; + break; + case '?': + default: + break; + } + + argc -= optind; + argv += optind; + + if (Hflag) + ftsoptions |= FTS_COMFOLLOW; + if (Lflag) { + ftsoptions &= ~FTS_PHYSICAL; + ftsoptions |= FTS_LOGICAL; + } + + /* + * Find first option to delimit the file list. The first argument + * that starts with a -, or is a ! or a ( must be interpreted as a + * part of the find expression, according to POSIX .2. + */ + for (; *argv != NULL; *p++ = *argv++) { + if (argv[0][0] == '-') + break; + if ((argv[0][0] == '!' || argv[0][0] == '(') && + argv[0][1] == '\0') + break; + } + + if (p == start) + usage(); + *p = NULL; + + if ((dotfd = open(".", O_RDONLY, 0)) < 0) + err(1, "."); + + exit(find_execute(find_formplan(argv), start)); +} + +static void +usage() +{ + (void)fprintf(stderr, +"usage: find [-H | -L | -P] [-Xdx] [-f file] [file ...] [expression]\n"); + exit(1); +} diff --git a/usr.bin/find/misc.c b/usr.bin/find/misc.c new file mode 100644 index 0000000..1db34ce --- /dev/null +++ b/usr.bin/find/misc.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "find.h" + +/* + * brace_subst -- + * Replace occurrences of {} in s1 with s2 and return the result string. + */ +void +brace_subst(orig, store, path, len) + char *orig, **store, *path; + int len; +{ + register int plen; + register char ch, *p; + + plen = strlen(path); + for (p = *store; (ch = *orig) != '\0'; ++orig) + if (ch == '{' && orig[1] == '}') { + while ((p - *store) + plen > len) + if (!(*store = realloc(*store, len *= 2))) + err(1, NULL); + memmove(p, path, plen); + p += plen; + ++orig; + } else + *p++ = ch; + *p = '\0'; +} + +/* + * queryuser -- + * print a message to standard error and then read input from standard + * input. If the input is 'y' then 1 is returned. + */ +int +queryuser(argv) + register char **argv; +{ + int ch, first, nl; + + (void)fprintf(stderr, "\"%s", *argv); + while (*++argv) + (void)fprintf(stderr, " %s", *argv); + (void)fprintf(stderr, "\"? "); + (void)fflush(stderr); + + first = ch = getchar(); + for (nl = 0;;) { + if (ch == '\n') { + nl = 1; + break; + } + if (ch == EOF) + break; + ch = getchar(); + } + + if (!nl) { + (void)fprintf(stderr, "\n"); + (void)fflush(stderr); + } + return (first == 'y'); +} + +/* + * emalloc -- + * malloc with error checking. + */ +void * +emalloc(len) + u_int len; +{ + void *p; + + if ((p = malloc(len)) == NULL) + err(1, NULL); + return (p); +} diff --git a/usr.bin/find/operator.c b/usr.bin/find/operator.c new file mode 100644 index 0000000..a706b88 --- /dev/null +++ b/usr.bin/find/operator.c @@ -0,0 +1,270 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include + +#include "find.h" + +/* + * yanknode -- + * destructively removes the top from the plan + */ +static PLAN * +yanknode(planp) + PLAN **planp; /* pointer to top of plan (modified) */ +{ + PLAN *node; /* top node removed from the plan */ + + if ((node = (*planp)) == NULL) + return (NULL); + (*planp) = (*planp)->next; + node->next = NULL; + return (node); +} + +/* + * yankexpr -- + * Removes one expression from the plan. This is used mainly by + * paren_squish. In comments below, an expression is either a + * simple node or a N_EXPR node containing a list of simple nodes. + */ +static PLAN * +yankexpr(planp) + PLAN **planp; /* pointer to top of plan (modified) */ +{ + register PLAN *next; /* temp node holding subexpression results */ + PLAN *node; /* pointer to returned node or expression */ + PLAN *tail; /* pointer to tail of subplan */ + PLAN *subplan; /* pointer to head of ( ) expression */ + int f_expr(); + + /* first pull the top node from the plan */ + if ((node = yanknode(planp)) == NULL) + return (NULL); + + /* + * If the node is an '(' then we recursively slurp up expressions + * until we find its associated ')'. If it's a closing paren we + * just return it and unwind our recursion; all other nodes are + * complete expressions, so just return them. + */ + if (node->type == N_OPENPAREN) + for (tail = subplan = NULL;;) { + if ((next = yankexpr(planp)) == NULL) + err(1, "(: missing closing ')'"); + /* + * If we find a closing ')' we store the collected + * subplan in our '(' node and convert the node to + * a N_EXPR. The ')' we found is ignored. Otherwise, + * we just continue to add whatever we get to our + * subplan. + */ + if (next->type == N_CLOSEPAREN) { + if (subplan == NULL) + errx(1, "(): empty inner expression"); + node->p_data[0] = subplan; + node->type = N_EXPR; + node->eval = f_expr; + break; + } else { + if (subplan == NULL) + tail = subplan = next; + else { + tail->next = next; + tail = next; + } + tail->next = NULL; + } + } + return (node); +} + +/* + * paren_squish -- + * replaces "parentheisized" plans in our search plan with "expr" nodes. + */ +PLAN * +paren_squish(plan) + PLAN *plan; /* plan with ( ) nodes */ +{ + register PLAN *expr; /* pointer to next expression */ + register PLAN *tail; /* pointer to tail of result plan */ + PLAN *result; /* pointer to head of result plan */ + + result = tail = NULL; + + /* + * the basic idea is to have yankexpr do all our work and just + * collect it's results together. + */ + while ((expr = yankexpr(&plan)) != NULL) { + /* + * if we find an unclaimed ')' it means there is a missing + * '(' someplace. + */ + if (expr->type == N_CLOSEPAREN) + errx(1, "): no beginning '('"); + + /* add the expression to our result plan */ + if (result == NULL) + tail = result = expr; + else { + tail->next = expr; + tail = expr; + } + tail->next = NULL; + } + return (result); +} + +/* + * not_squish -- + * compresses "!" expressions in our search plan. + */ +PLAN * +not_squish(plan) + PLAN *plan; /* plan to process */ +{ + register PLAN *next; /* next node being processed */ + register PLAN *node; /* temporary node used in N_NOT processing */ + register PLAN *tail; /* pointer to tail of result plan */ + PLAN *result; /* pointer to head of result plan */ + + tail = result = next = NULL; + + while ((next = yanknode(&plan)) != NULL) { + /* + * if we encounter a ( expression ) then look for nots in + * the expr subplan. + */ + if (next->type == N_EXPR) + next->p_data[0] = not_squish(next->p_data[0]); + + /* + * if we encounter a not, then snag the next node and place + * it in the not's subplan. As an optimization we compress + * several not's to zero or one not. + */ + if (next->type == N_NOT) { + int notlevel = 1; + + node = yanknode(&plan); + while (node->type == N_NOT) { + ++notlevel; + node = yanknode(&plan); + } + if (node == NULL) + errx(1, "!: no following expression"); + if (node->type == N_OR) + errx(1, "!: nothing between ! and -o"); + if (notlevel % 2 != 1) + next = node; + else + next->p_data[0] = node; + } + + /* add the node to our result plan */ + if (result == NULL) + tail = result = next; + else { + tail->next = next; + tail = next; + } + tail->next = NULL; + } + return (result); +} + +/* + * or_squish -- + * compresses -o expressions in our search plan. + */ +PLAN * +or_squish(plan) + PLAN *plan; /* plan with ors to be squished */ +{ + register PLAN *next; /* next node being processed */ + register PLAN *tail; /* pointer to tail of result plan */ + PLAN *result; /* pointer to head of result plan */ + + tail = result = next = NULL; + + while ((next = yanknode(&plan)) != NULL) { + /* + * if we encounter a ( expression ) then look for or's in + * the expr subplan. + */ + if (next->type == N_EXPR) + next->p_data[0] = or_squish(next->p_data[0]); + + /* if we encounter a not then look for not's in the subplan */ + if (next->type == N_NOT) + next->p_data[0] = or_squish(next->p_data[0]); + + /* + * if we encounter an or, then place our collected plan in the + * or's first subplan and then recursively collect the + * remaining stuff into the second subplan and return the or. + */ + if (next->type == N_OR) { + if (result == NULL) + errx(1, "-o: no expression before -o"); + next->p_data[0] = result; + next->p_data[1] = or_squish(plan); + if (next->p_data[1] == NULL) + errx(1, "-o: no expression after -o"); + return (next); + } + + /* add the node to our result plan */ + if (result == NULL) + tail = result = next; + else { + tail->next = next; + tail = next; + } + tail->next = NULL; + } + return (result); +} diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c new file mode 100644 index 0000000..9b25cee --- /dev/null +++ b/usr.bin/find/option.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)option.c 8.2 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "find.h" + +static OPTION *option __P((char *)); + +/* NB: the following table must be sorted lexically. */ +static OPTION const options[] = { + { "!", N_NOT, c_not, O_ZERO }, + { "(", N_OPENPAREN, c_openparen, O_ZERO }, + { ")", N_CLOSEPAREN, c_closeparen, O_ZERO }, + { "-a", N_AND, NULL, O_NONE }, + { "-and", N_AND, NULL, O_NONE }, + { "-atime", N_ATIME, c_atime, O_ARGV }, + { "-ctime", N_CTIME, c_ctime, O_ARGV }, + { "-depth", N_DEPTH, c_depth, O_ZERO }, + { "-exec", N_EXEC, c_exec, O_ARGVP }, + { "-follow", N_FOLLOW, c_follow, O_ZERO }, + { "-fstype", N_FSTYPE, c_fstype, O_ARGV }, + { "-group", N_GROUP, c_group, O_ARGV }, + { "-inum", N_INUM, c_inum, O_ARGV }, + { "-links", N_LINKS, c_links, O_ARGV }, + { "-ls", N_LS, c_ls, O_ZERO }, + { "-mtime", N_MTIME, c_mtime, O_ARGV }, + { "-name", N_NAME, c_name, O_ARGV }, + { "-newer", N_NEWER, c_newer, O_ARGV }, + { "-nogroup", N_NOGROUP, c_nogroup, O_ZERO }, + { "-nouser", N_NOUSER, c_nouser, O_ZERO }, + { "-o", N_OR, c_or, O_ZERO }, + { "-ok", N_OK, c_exec, O_ARGVP }, + { "-or", N_OR, c_or, O_ZERO }, + { "-path", N_PATH, c_path, O_ARGV }, + { "-perm", N_PERM, c_perm, O_ARGV }, + { "-print", N_PRINT, c_print, O_ZERO }, + { "-prune", N_PRUNE, c_prune, O_ZERO }, + { "-size", N_SIZE, c_size, O_ARGV }, + { "-type", N_TYPE, c_type, O_ARGV }, + { "-user", N_USER, c_user, O_ARGV }, + { "-xdev", N_XDEV, c_xdev, O_ZERO }, +}; + +/* + * find_create -- + * create a node corresponding to a command line argument. + * + * TODO: + * add create/process function pointers to node, so we can skip + * this switch stuff. + */ +PLAN * +find_create(argvp) + char ***argvp; +{ + register OPTION *p; + PLAN *new; + char **argv; + + argv = *argvp; + + if ((p = option(*argv)) == NULL) + errx(1, "%s: unknown option", *argv); + ++argv; + if (p->flags & (O_ARGV|O_ARGVP) && !*argv) + errx(1, "%s: requires additional arguments", *--argv); + + switch(p->flags) { + case O_NONE: + new = NULL; + break; + case O_ZERO: + new = (p->create)(); + break; + case O_ARGV: + new = (p->create)(*argv++); + break; + case O_ARGVP: + new = (p->create)(&argv, p->token == N_OK); + break; + default: + abort(); + } + *argvp = argv; + return (new); +} + +static OPTION * +option(name) + char *name; +{ + OPTION tmp; + int typecompare __P((const void *, const void *)); + + tmp.name = name; + return ((OPTION *)bsearch(&tmp, options, + sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare)); +} + +int +typecompare(a, b) + const void *a, *b; +{ + return (strcmp(((OPTION *)a)->name, ((OPTION *)b)->name)); +} diff --git a/usr.bin/finger/Makefile b/usr.bin/finger/Makefile new file mode 100644 index 0000000..944f1d0 --- /dev/null +++ b/usr.bin/finger/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= finger +SRCS= finger.c lprint.c net.c sprint.c util.c + +.include diff --git a/usr.bin/finger/extern.h b/usr.bin/finger/extern.h new file mode 100644 index 0000000..2b675f1 --- /dev/null +++ b/usr.bin/finger/extern.h @@ -0,0 +1,50 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +extern char tbuf[1024]; /* Temp buffer for anybody. */ +extern int entries; /* Number of people. */ +extern DB *db; /* Database. */ + +void enter_lastlog __P((PERSON *)); +PERSON *enter_person __P((struct passwd *)); +void enter_where __P((struct utmp *, PERSON *)); +void err __P((const char *, ...)); +PERSON *find_person __P((char *)); +void lflag_print __P((void)); +int match __P((struct passwd *, char *)); +void netfinger __P((char *)); +PERSON *palloc __P((void)); +char *prphone __P((char *)); +void sflag_print __P((void)); diff --git a/usr.bin/finger/finger.1 b/usr.bin/finger/finger.1 new file mode 100644 index 0000000..069f9cd --- /dev/null +++ b/usr.bin/finger/finger.1 @@ -0,0 +1,161 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)finger.1 8.2 (Berkeley) 2/16/94 +.\" +.Dd February 16, 1994 +.Dt FINGER 1 +.Os BSD 4 +.Sh NAME +.Nm finger +.Nd user information lookup program +.Sh SYNOPSIS +.Nm finger +.Op Fl lmsp +.Op Ar user ... +.Op Ar user@host ... +.Sh DESCRIPTION +The +.Nm finger +displays information about the system users. +.Pp +Options are: +.Bl -tag -width flag +.It Fl s +.Nm Finger +displays the user's login name, real name, terminal name and write +status (as a ``*'' before the terminal name if write permission is +denied), idle time, login time, office location and office phone +number. +.Pp +Idle time is in minutes if it is a single integer, hours and minutes +if a ``:'' is present, or days if a ``d'' is present. +Login time is displayed as month, day, hours and minutes, unless +more than six months ago, in which case the year is displayed rather +than the hours and minutes. +.Pp +Unknown devices as well as nonexistent idle and login times are +displayed as single asterisks. +.Pp +.It Fl l +Produces a multi-line format displaying all of the information +described for the +.Fl s +option as well as the user's home directory, home phone number, login +shell, and the contents of the files +.Dq Pa .forward , +.Dq Pa .plan +and +.Dq Pa .project +from the user's home directory. +.Pp +If idle time is at least a minute and less than a day, it is +presented in the form ``hh:mm''. +Idle times greater than a day are presented as ``d day[s]hh:mm''. +.Pp +Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''. +Numbers specified as ten or seven digits are printed as the appropriate +subset of that string. +Numbers specified as five digits are printed as ``xN-NNNN''. +.Pp +If write permission is denied to the device, the phrase ``(messages off)'' +is appended to the line containing the device name. +One entry per user is displayed with the +.Fl l +option; if a user is logged on multiple times, terminal information +is repeated once per login. +.Pp +.It Fl p +Prevents +the +.Fl l +option of +.Nm finger +from displaying the contents of the +.Dq Pa .forward , +.Dq Pa .plan +and +.Dq Pa .project +files. +.It Fl m +Prevent matching of +.Ar user +names. +.Ar User +is usually a login name; however, matching will also be done on the +users' real names, unless the +.Fl m +option is supplied. +All name matching performed by +.Nm finger +is case insensitive. +.El +.Pp +If no options are specified, +.Nm finger +defaults to the +.Fl l +style output if operands are provided, otherwise to the +.Fl s +style. +Note that some fields may be missing, in either format, if information +is not available for them. +.Pp +If no arguments are specified, +.Nm finger +will print an entry for each user currently logged into the system. +.Pp +.Nm Finger +may be used to look up users on a remote machine. +The format is to specify a +.Ar user +as +.Dq Li user@host , +or +.Dq Li @host , +where the default output +format for the former is the +.Fl l +style, and the default output format for the latter is the +.Fl s +style. +The +.Fl l +option is the only option that may be passed to a remote machine. +.Sh SEE ALSO +.Xr chpass 1 , +.Xr w 1 , +.Xr who 1 , +.Sh HISTORY +The +.Nm finger +command appeared in +.Bx 3.0 . diff --git a/usr.bin/finger/finger.c b/usr.bin/finger/finger.c new file mode 100644 index 0000000..5a16765 --- /dev/null +++ b/usr.bin/finger/finger.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)finger.c 8.2 (Berkeley) 9/30/93"; +#endif /* not lint */ + +/* + * Finger prints out information about users. It is not portable since + * certain fields (e.g. the full user name, office, and phone numbers) are + * extracted from the gecos field of the passwd file which other UNIXes + * may not have or may use for other things. + * + * There are currently two output formats; the short format is one line + * per user and displays login name, tty, login time, real name, idle time, + * and office location/phone number. The long format gives the same + * information (in a more legible format) as well as home directory, shell, + * mail info, and .plan/.project files. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finger.h" + +DB *db; +time_t now; +int entries, lflag, mflag, pplan, sflag; +char tbuf[1024]; + +static void loginlist __P((void)); +static void userlist __P((int, char **)); + +main(argc, argv) + int argc; + char **argv; +{ + int ch; + + while ((ch = getopt(argc, argv, "lmps")) != EOF) + switch(ch) { + case 'l': + lflag = 1; /* long format */ + break; + case 'm': + mflag = 1; /* force exact match of names */ + break; + case 'p': + pplan = 1; /* don't show .plan/.project */ + break; + case 's': + sflag = 1; /* short format */ + break; + case '?': + default: + (void)fprintf(stderr, + "usage: finger [-lmps] [login ...]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + (void)time(&now); + setpassent(1); + if (!*argv) { + /* + * Assign explicit "small" format if no names given and -l + * not selected. Force the -s BEFORE we get names so proper + * screening will be done. + */ + if (!lflag) + sflag = 1; /* if -l not explicit, force -s */ + loginlist(); + if (entries == 0) + (void)printf("No one logged on.\n"); + } else { + userlist(argc, argv); + /* + * Assign explicit "large" format if names given and -s not + * explicitly stated. Force the -l AFTER we get names so any + * remote finger attempts specified won't be mishandled. + */ + if (!sflag) + lflag = 1; /* if -s not explicit, force -l */ + } + if (entries) + if (lflag) + lflag_print(); + else + sflag_print(); + exit(0); +} + +static void +loginlist() +{ + register PERSON *pn; + DBT data, key; + struct passwd *pw; + struct utmp user; + int r, sflag; + char name[UT_NAMESIZE + 1]; + + if (!freopen(_PATH_UTMP, "r", stdin)) + err("%s: %s", _PATH_UTMP, strerror(errno)); + name[UT_NAMESIZE] = NULL; + while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { + if (!user.ut_name[0]) + continue; + if ((pn = find_person(user.ut_name)) == NULL) { + bcopy(user.ut_name, name, UT_NAMESIZE); + if ((pw = getpwnam(name)) == NULL) + continue; + pn = enter_person(pw); + } + enter_where(&user, pn); + } + if (db && lflag) + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err("db seq: %s", strerror(errno)); + if (r == 1) + break; + enter_lastlog(*(PERSON **)data.data); + } +} + +static void +userlist(argc, argv) + register int argc; + register char **argv; +{ + register PERSON *pn; + DBT data, key; + struct utmp user; + struct passwd *pw; + int r, sflag, *used, *ip; + char **ap, **nargv, **np, **p; + + if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || + (used = calloc(argc, sizeof(int))) == NULL) + err("%s", strerror(errno)); + + /* Pull out all network requests. */ + for (ap = p = argv, np = nargv; *p; ++p) + if (index(*p, '@')) + *np++ = *p; + else + *ap++ = *p; + + *np++ = NULL; + *ap++ = NULL; + + if (!*argv) + goto net; + + /* + * Traverse the list of possible login names and check the login name + * and real name against the name specified by the user. + */ + if (mflag) + for (p = argv; *p; ++p) + if (pw = getpwnam(*p)) + enter_person(pw); + else + (void)fprintf(stderr, + "finger: %s: no such user\n", *p); + else { + while (pw = getpwent()) + for (p = argv, ip = used; *p; ++p, ++ip) + if (match(pw, *p)) { + enter_person(pw); + *ip = 1; + } + for (p = argv, ip = used; *p; ++p, ++ip) + if (!*ip) + (void)fprintf(stderr, + "finger: %s: no such user\n", *p); + } + + /* Handle network requests. */ +net: for (p = nargv; *p;) + netfinger(*p++); + + if (entries == 0) + return; + + /* + * Scan thru the list of users currently logged in, saving + * appropriate data whenever a match occurs. + */ + if (!freopen(_PATH_UTMP, "r", stdin)) + err("%s: %s", _PATH_UTMP, strerror(errno)); + while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { + if (!user.ut_name[0]) + continue; + if ((pn = find_person(user.ut_name)) == NULL) + continue; + enter_where(&user, pn); + } + if (db) + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err("db seq: %s", strerror(errno)); + if (r == 1) + break; + enter_lastlog(*(PERSON **)data.data); + } +} diff --git a/usr.bin/finger/finger.h b/usr.bin/finger/finger.h new file mode 100644 index 0000000..5104425 --- /dev/null +++ b/usr.bin/finger/finger.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)finger.h 8.1 (Berkeley) 6/6/93 + */ + +typedef struct person { + uid_t uid; /* user id */ + char *dir; /* user's home directory */ + char *homephone; /* pointer to home phone no. */ + char *name; /* login name */ + char *office; /* pointer to office name */ + char *officephone; /* pointer to office phone no. */ + char *realname; /* pointer to full name */ + char *shell; /* user's shell */ + struct where *whead, *wtail; /* list of where user is or has been */ +} PERSON; + +enum status { LASTLOG, LOGGEDIN }; + +typedef struct where { + struct where *next; /* next place user is or has been */ + enum status info; /* type/status of request */ + short writable; /* tty is writable */ + time_t loginat; /* time of (last) login */ + time_t idletime; /* how long idle (if logged in) */ + char tty[UT_LINESIZE+1]; /* null terminated tty line */ + char host[UT_HOSTSIZE+1]; /* null terminated remote host name */ +} WHERE; + +#include "extern.h" diff --git a/usr.bin/finger/lprint.c b/usr.bin/finger/lprint.c new file mode 100644 index 0000000..d079c24 --- /dev/null +++ b/usr.bin/finger/lprint.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lprint.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finger.h" + +#define LINE_LEN 80 +#define TAB_LEN 8 /* 8 spaces between tabs */ +#define _PATH_FORWARD ".forward" +#define _PATH_PLAN ".plan" +#define _PATH_PROJECT ".project" + +static int demi_print __P((char *, int)); +static void lprint __P((PERSON *)); +static int show_text __P((char *, char *, char *)); +static void vputc __P((int)); + +void +lflag_print() +{ + extern int pplan; + register PERSON *pn; + register int sflag, r; + DBT data, key; + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err("db seq: %s", strerror(errno)); + if (r == 1) + break; + pn = *(PERSON **)data.data; + if (sflag != R_FIRST) + putchar('\n'); + lprint(pn); + if (!pplan) { + (void)show_text(pn->dir, + _PATH_FORWARD, "Mail forwarded to"); + (void)show_text(pn->dir, _PATH_PROJECT, "Project"); + if (!show_text(pn->dir, _PATH_PLAN, "Plan")) + (void)printf("No Plan.\n"); + } + } +} + +static void +lprint(pn) + register PERSON *pn; +{ + extern time_t now; + register struct tm *delta; + register WHERE *w; + register int cpr, len, maxlen; + struct tm *tp; + int oddfield; + char *t, *tzn; + + /* + * long format -- + * login name + * real name + * home directory + * shell + * office, office phone, home phone if available + */ + (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", + pn->name, pn->realname, pn->dir); + (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); + + /* + * try and print office, office phone, and home phone on one line; + * if that fails, do line filling so it looks nice. + */ +#define OFFICE_TAG "Office" +#define OFFICE_PHONE_TAG "Office Phone" + oddfield = 0; + if (pn->office && pn->officephone && + strlen(pn->office) + strlen(pn->officephone) + + sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s", + OFFICE_TAG, pn->office, prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } else { + if (pn->office) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", + OFFICE_TAG, pn->office); + oddfield = demi_print(tbuf, oddfield); + } + if (pn->officephone) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", + OFFICE_PHONE_TAG, prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } + } + if (pn->homephone) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone", + prphone(pn->homephone)); + oddfield = demi_print(tbuf, oddfield); + } + if (oddfield) + putchar('\n'); + + /* + * long format con't: * if logged in + * terminal + * idle time + * if messages allowed + * where logged in from + * if not logged in + * when last logged in + */ + /* find out longest device name for this user for formatting */ + for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) + if ((len = strlen(w->tty)) > maxlen) + maxlen = len; + /* find rest of entries for user */ + for (w = pn->whead; w != NULL; w = w->next) { + switch (w->info) { + case LOGGEDIN: + tp = localtime(&w->loginat); + t = asctime(tp); + tzn = tp->tm_zone; + cpr = printf("On since %.16s (%s) on %s", + t, tzn, w->tty); + /* + * idle time is tough; if have one, print a comma, + * then spaces to pad out the device name, then the + * idle time. Follow with a comma if a remote login. + */ + delta = gmtime(&w->idletime); + if (delta->tm_yday || delta->tm_hour || delta->tm_min) { + cpr += printf("%-*s idle ", + maxlen - strlen(w->tty) + 1, ","); + if (delta->tm_yday > 0) { + cpr += printf("%d day%s ", + delta->tm_yday, + delta->tm_yday == 1 ? "" : "s"); + } + cpr += printf("%d:%02d", + delta->tm_hour, delta->tm_min); + if (*w->host) { + putchar(','); + ++cpr; + } + } + if (!w->writable) + cpr += printf(" (messages off)"); + break; + case LASTLOG: + if (w->loginat == 0) { + (void)printf("Never logged in."); + break; + } + tp = localtime(&w->loginat); + t = asctime(tp); + tzn = tp->tm_zone; + if (now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2) + cpr = + printf("Last login %.16s %.4s (%s) on %s", + t, t + 20, tzn, w->tty); + else + cpr = printf("Last login %.16s (%s) on %s", + t, tzn, w->tty); + break; + } + if (*w->host) { + if (LINE_LEN < (cpr + 6 + strlen(w->host))) + (void)printf("\n "); + (void)printf(" from %s", w->host); + } + putchar('\n'); + } +} + +static int +demi_print(str, oddfield) + char *str; + int oddfield; +{ + static int lenlast; + int lenthis, maxlen; + + lenthis = strlen(str); + if (oddfield) { + /* + * We left off on an odd number of fields. If we haven't + * crossed the midpoint of the screen, and we have room for + * the next field, print it on the same line; otherwise, + * print it on a new line. + * + * Note: we insist on having the right hand fields start + * no less than 5 tabs out. + */ + maxlen = 5 * TAB_LEN; + if (maxlen < lenlast) + maxlen = lenlast; + if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + + lenthis) <= LINE_LEN) { + while(lenlast < (4 * TAB_LEN)) { + putchar('\t'); + lenlast += TAB_LEN; + } + (void)printf("\t%s\n", str); /* force one tab */ + } else { + (void)printf("\n%s", str); /* go to next line */ + oddfield = !oddfield; /* this'll be undone below */ + } + } else + (void)printf("%s", str); + oddfield = !oddfield; /* toggle odd/even marker */ + lenlast = lenthis; + return(oddfield); +} + +static int +show_text(directory, file_name, header) + char *directory, *file_name, *header; +{ + struct stat sb; + register FILE *fp; + register int ch, cnt, lastc; + register char *p; + int fd, nr; + + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); + if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || + sb.st_size == 0) + return(0); + + /* If short enough, and no newlines, show it on a single line.*/ + if (sb.st_size <= LINE_LEN - strlen(header) - 5) { + nr = read(fd, tbuf, sizeof(tbuf)); + if (nr <= 0) { + (void)close(fd); + return(0); + } + for (p = tbuf, cnt = nr; cnt--; ++p) + if (*p == '\n') + break; + if (cnt <= 1) { + (void)printf("%s: ", header); + for (p = tbuf, cnt = nr; cnt--; ++p) + vputc(lastc = *p); + if (lastc != '\n') + (void)putchar('\n'); + (void)close(fd); + return(1); + } + else + (void)lseek(fd, 0L, SEEK_SET); + } + if ((fp = fdopen(fd, "r")) == NULL) + return(0); + (void)printf("%s:\n", header); + while ((ch = getc(fp)) != EOF) + vputc(lastc = ch); + if (lastc != '\n') + (void)putchar('\n'); + (void)fclose(fp); + return(1); +} + +static void +vputc(ch) + register int ch; +{ + int meta; + + if (!isascii(ch)) { + (void)putchar('M'); + (void)putchar('-'); + ch = toascii(ch); + meta = 1; + } else + meta = 0; + if (isprint(ch) || !meta && (ch == ' ' || ch == '\t' || ch == '\n')) + (void)putchar(ch); + else { + (void)putchar('^'); + (void)putchar(ch == '\177' ? '?' : ch | 0100); + } +} diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c new file mode 100644 index 0000000..51f1b43 --- /dev/null +++ b/usr.bin/finger/net.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)net.c 8.3 (Berkeley) 1/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finger.h" + +void +netfinger(name) + char *name; +{ + extern int lflag; + register FILE *fp; + register int c, lastc; + struct in_addr defaddr; + struct hostent *hp, def; + struct servent *sp; + struct sockaddr_in sin; + int s; + char *alist[1], *host; + + if (!(host = rindex(name, '@'))) + return; + *host++ = NULL; + if (isdigit(*host) && (defaddr.s_addr = inet_addr(host)) != -1) { + def.h_name = host; + def.h_addr_list = alist; + def.h_addr = (char *)&defaddr; + def.h_length = sizeof(struct in_addr); + def.h_addrtype = AF_INET; + def.h_aliases = 0; + hp = &def; + } else if (!(hp = gethostbyname(host))) { + (void)fprintf(stderr, + "finger: unknown host: %s\n", host); + return; + } + if (!(sp = getservbyname("finger", "tcp"))) { + (void)fprintf(stderr, "finger: tcp/finger: unknown service\n"); + return; + } + sin.sin_family = hp->h_addrtype; + bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); + sin.sin_port = sp->s_port; + if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { + perror("finger: socket"); + return; + } + + /* have network connection; identify the host connected with */ + (void)printf("[%s]\n", hp->h_name); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + perror("finger: connect"); + (void)close(s); + return; + } + + /* -l flag for remote fingerd */ + if (lflag) + write(s, "/W ", 3); + /* send the name followed by */ + (void)write(s, name, strlen(name)); + (void)write(s, "\r\n", 2); + + /* + * Read from the remote system; once we're connected, we assume some + * data. If none arrives, we hang until the user interrupts. + * + * If we see a or a with the high bit set, treat it as + * a newline; if followed by a newline character, only output one + * newline. + * + * Otherwise, all high bits are stripped; if it isn't printable and + * it isn't a space, we can simply set the 7th bit. Every ASCII + * character with bit 7 set is printable. + */ + if (fp = fdopen(s, "r")) + while ((c = getc(fp)) != EOF) { + c &= 0x7f; + if (c == 0x0d) { + if (lastc == '\r') /* ^M^M - skip dupes */ + continue; + c = '\n'; + lastc = '\r'; + } else { + if (!isprint(c) && !isspace(c)) + c |= 0x40; + if (lastc != '\r' || c != '\n') + lastc = c; + else { + lastc = '\n'; + continue; + } + } + putchar(c); + } + if (lastc != '\n') + putchar('\n'); + putchar('\n'); + (void)fclose(fp); +} diff --git a/usr.bin/finger/sprint.c b/usr.bin/finger/sprint.c new file mode 100644 index 0000000..68deb76 --- /dev/null +++ b/usr.bin/finger/sprint.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)sprint.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finger.h" + +static void stimeprint __P((WHERE *)); + +void +sflag_print() +{ + extern time_t now; + register PERSON *pn; + register WHERE *w; + register int sflag, r; + register char *p; + DBT data, key; + + /* + * short format -- + * login name + * real name + * terminal name (the XX of ttyXX) + * if terminal writeable (add an '*' to the terminal name + * if not) + * if logged in show idle time and day logged in, else + * show last login date and time. If > 6 moths, + * show year instead of time. + * office location + * office phone + */ +#define MAXREALNAME 20 + (void)printf("%-*s %-*s %s\n", UT_NAMESIZE, "Login", MAXREALNAME, + "Name", "Tty Idle Login Time Office Office Phone"); + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err("db seq: %s", strerror(errno)); + if (r == 1) + break; + pn = *(PERSON **)data.data; + + for (w = pn->whead; w != NULL; w = w->next) { + (void)printf("%-*.*s %-*.*s ", UT_NAMESIZE, UT_NAMESIZE, + pn->name, MAXREALNAME, MAXREALNAME, + pn->realname ? pn->realname : ""); + if (!w->loginat) { + (void)printf(" * * No logins "); + goto office; + } + (void)putchar(w->info == LOGGEDIN && !w->writable ? + '*' : ' '); + if (*w->tty) + (void)printf("%-2.2s ", + w->tty[0] != 't' || w->tty[1] != 't' || + w->tty[2] != 'y' ? w->tty : w->tty + 3); + else + (void)printf(" "); + if (w->info == LOGGEDIN) { + stimeprint(w); + (void)printf(" "); + } else + (void)printf(" * "); + p = ctime(&w->loginat); + (void)printf("%.6s", p + 4); + if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2) + (void)printf(" %.4s", p + 20); + else + (void)printf(" %.5s", p + 11); +office: if (pn->office) + (void)printf(" %-10.10s", pn->office); + else if (pn->officephone) + (void)printf(" %-10.10s", " "); + if (pn->officephone) + (void)printf(" %-.15s", + prphone(pn->officephone)); + putchar('\n'); + } + } +} + +static void +stimeprint(w) + WHERE *w; +{ + register struct tm *delta; + + delta = gmtime(&w->idletime); + if (!delta->tm_yday) + if (!delta->tm_hour) + if (!delta->tm_min) + (void)printf(" "); + else + (void)printf("%5d", delta->tm_min); + else + (void)printf("%2d:%02d", + delta->tm_hour, delta->tm_min); + else + (void)printf("%4dd", delta->tm_yday); +} diff --git a/usr.bin/finger/util.c b/usr.bin/finger/util.c new file mode 100644 index 0000000..c27cf1b --- /dev/null +++ b/usr.bin/finger/util.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finger.h" + +static void find_idle_and_ttywrite __P((WHERE *)); +static void userinfo __P((PERSON *, struct passwd *)); +static WHERE *walloc __P((PERSON *)); + +int +match(pw, user) + struct passwd *pw; + char *user; +{ + register char *p, *t; + char name[1024]; + + if (!strcasecmp(pw->pw_name, user)) + return(1); + + /* + * XXX + * Why do we skip asterisks!?!? + */ + (void)strcpy(p = tbuf, pw->pw_gecos); + if (*p == '*') + ++p; + + /* Ampersands get replaced by the login name. */ + if ((p = strtok(p, ",")) == NULL) + return(0); + + for (t = name; *t = *p; ++p) + if (*t == '&') { + (void)strcpy(t, pw->pw_name); + while (*++t); + } + else + ++t; + for (t = name; p = strtok(t, "\t "); t = NULL) + if (!strcasecmp(p, user)) + return(1); + return(0); +} + +void +enter_lastlog(pn) + register PERSON *pn; +{ + register WHERE *w; + static int opened, fd; + struct lastlog ll; + char doit = 0; + + /* some systems may not maintain lastlog, don't report errors. */ + if (!opened) { + fd = open(_PATH_LASTLOG, O_RDONLY, 0); + opened = 1; + } + if (fd == -1 || + lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != + (long)pn->uid * sizeof(ll) || + read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { + /* as if never logged in */ + ll.ll_line[0] = ll.ll_host[0] = NULL; + ll.ll_time = 0; + } + if ((w = pn->whead) == NULL) + doit = 1; + else if (ll.ll_time != 0) { + /* if last login is earlier than some current login */ + for (; !doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && w->loginat < ll.ll_time) + doit = 1; + /* + * and if it's not any of the current logins + * can't use time comparison because there may be a small + * discrepency since login calls time() twice + */ + for (w = pn->whead; doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && + strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) + doit = 0; + } + if (doit) { + w = walloc(pn); + w->info = LASTLOG; + bcopy(ll.ll_line, w->tty, UT_LINESIZE); + w->tty[UT_LINESIZE] = 0; + bcopy(ll.ll_host, w->host, UT_HOSTSIZE); + w->host[UT_HOSTSIZE] = 0; + w->loginat = ll.ll_time; + } +} + +void +enter_where(ut, pn) + struct utmp *ut; + PERSON *pn; +{ + register WHERE *w; + + w = walloc(pn); + w->info = LOGGEDIN; + bcopy(ut->ut_line, w->tty, UT_LINESIZE); + w->tty[UT_LINESIZE] = 0; + bcopy(ut->ut_host, w->host, UT_HOSTSIZE); + w->host[UT_HOSTSIZE] = 0; + w->loginat = (time_t)ut->ut_time; + find_idle_and_ttywrite(w); +} + +PERSON * +enter_person(pw) + register struct passwd *pw; +{ + DBT data, key; + PERSON *pn; + + if (db == NULL && + (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) + err("%s", strerror(errno)); + + key.data = pw->pw_name; + key.size = strlen(pw->pw_name); + + switch((*db->get)(db, &key, &data, 0)) { + case 0: + return(*(PERSON **)data.data); + default: + case -1: + err("db get: %s", strerror(errno)); + /* NOTREACHED */ + case 1: + ++entries; + pn = palloc(); + userinfo(pn, pw); + pn->whead = NULL; + + data.size = sizeof(PERSON *); + data.data = &pn; + if ((*db->put)(db, &key, &data, 0)) + err("%s", strerror(errno)); + return(pn); + } +} + +PERSON * +find_person(name) + char *name; +{ + register int cnt; + DBT data, key; + char buf[UT_NAMESIZE + 1]; + + if (!db) + return(NULL); + + /* Name may be only UT_NAMESIZE long and not NUL terminated. */ + for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) + buf[cnt] = *name; + buf[cnt] = '\0'; + key.data = buf; + key.size = cnt; + + return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); +} + +PERSON * +palloc() +{ + PERSON *p; + + if ((p = malloc((u_int) sizeof(PERSON))) == NULL) + err("%s", strerror(errno)); + return(p); +} + +static WHERE * +walloc(pn) + register PERSON *pn; +{ + register WHERE *w; + + if ((w = malloc((u_int) sizeof(WHERE))) == NULL) + err("%s", strerror(errno)); + if (pn->whead == NULL) + pn->whead = pn->wtail = w; + else { + pn->wtail->next = w; + pn->wtail = w; + } + w->next = NULL; + return(w); +} + +char * +prphone(num) + char *num; +{ + register char *p; + int len; + static char pbuf[15]; + + /* don't touch anything if the user has their own formatting */ + for (p = num; *p; ++p) + if (!isdigit(*p)) + return(num); + len = p - num; + p = pbuf; + switch(len) { + case 11: /* +0-123-456-7890 */ + *p++ = '+'; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 10: /* 012-345-6789 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 7: /* 012-3456 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + break; + case 5: /* x0-1234 */ + *p++ = 'x'; + *p++ = *num++; + break; + default: + return(num); + } + *p++ = '-'; + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p = '\0'; + return(pbuf); +} + +static void +find_idle_and_ttywrite(w) + register WHERE *w; +{ + extern time_t now; + struct stat sb; + + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); + if (stat(tbuf, &sb) < 0) { + (void)fprintf(stderr, + "finger: %s: %s\n", tbuf, strerror(errno)); + return; + } + w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; + +#define TALKABLE 0220 /* tty is writable if 220 mode */ + w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); +} + +static void +userinfo(pn, pw) + register PERSON *pn; + register struct passwd *pw; +{ + register char *p, *t; + char *bp, name[1024]; + + pn->realname = pn->office = pn->officephone = pn->homephone = NULL; + + pn->uid = pw->pw_uid; + pn->name = strdup(pw->pw_name); + pn->dir = strdup(pw->pw_dir); + pn->shell = strdup(pw->pw_shell); + + /* why do we skip asterisks!?!? */ + (void)strcpy(bp = tbuf, pw->pw_gecos); + if (*bp == '*') + ++bp; + + /* ampersands get replaced by the login name */ + if (!(p = strsep(&bp, ","))) + return; + for (t = name; *t = *p; ++p) + if (*t == '&') { + (void)strcpy(t, pw->pw_name); + if (islower(*t)) + *t = toupper(*t); + while (*++t); + } + else + ++t; + pn->realname = strdup(name); + pn->office = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->officephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->homephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "finger: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/fmt/Makefile b/usr.bin/fmt/Makefile new file mode 100644 index 0000000..7a51add --- /dev/null +++ b/usr.bin/fmt/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fmt +SRCS= fmt.c head.c +.PATH: ${.CURDIR}/../mail + +.include diff --git a/usr.bin/fmt/fmt.1 b/usr.bin/fmt/fmt.1 new file mode 100644 index 0000000..4c76cc7 --- /dev/null +++ b/usr.bin/fmt/fmt.1 @@ -0,0 +1,89 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)fmt.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt FMT 1 +.Os +.Sh NAME +.Nm fmt +.Nd simple text formatter +.Sh SYNOPSIS +.Nm fmt +.Oo +.Ar goal +.Op Ar maximum +.Oc +.Op name ... +.Sh DESCRIPTION +.Nm Fmt +is a simple text formatter which reads the concatenation of input +files (or standard input if none are given) and produces on standard +output a version of its input with lines as close to the +.Ar goal +length +as possible without exceeding the maximum. The +.Ar goal +length defaults +to 65 and the maximum to 75. The spacing at the beginning of the +input lines is preserved in the output, as are blank lines and +interword spacing. +.Pp +.Nm Fmt +is meant to format mail messages prior to sending, but may also be useful +for other simple tasks. +For instance, +within visual mode of the +.Xr ex 1 +editor (e.g. +.Xr vi 1 ) +the command +.Pp +.Dl \&!}fmt +.Pp +will reformat a paragraph, +evening the lines. +.Sh SEE ALSO +.Xr nroff 1 , +.Xr mail 1 +.Sh HISTORY +The +.Nm fmt +command appeared in +.Bx 3 . +.\" .Sh AUTHOR +.\" Kurt Shoens +.\" .br +.\" Liz Allen (added goal length concept) +.Sh BUGS +The program was designed to be simple and fast \- for more complex +operations, the standard text processors are likely to be more appropriate. diff --git a/usr.bin/fmt/fmt.c b/usr.bin/fmt/fmt.c new file mode 100644 index 0000000..565adf4 --- /dev/null +++ b/usr.bin/fmt/fmt.c @@ -0,0 +1,467 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93"; +#endif /* not lint */ + +#include +#include + +/* + * fmt -- format the concatenation of input files or standard input + * onto standard output. Designed for use with Mail ~| + * + * Syntax : fmt [ goal [ max ] ] [ name ... ] + * Authors: Kurt Shoens (UCB) 12/7/78; + * Liz Allen (UMCP) 2/24/83 [Addition of goal length concept]. + */ + +/* LIZ@UOM 6/18/85 -- Don't need LENGTH any more. + * #define LENGTH 72 Max line length in output + */ +#define NOSTR ((char *) 0) /* Null string pointer for lint */ + +/* LIZ@UOM 6/18/85 --New variables goal_length and max_length */ +#define GOAL_LENGTH 65 +#define MAX_LENGTH 75 +int goal_length; /* Target or goal line length in output */ +int max_length; /* Max line length in output */ +int pfx; /* Current leading blank count */ +int lineno; /* Current input line */ +int mark; /* Last place we saw a head line */ + +char *malloc(); /* for lint . . . */ +char *headnames[] = {"To", "Subject", "Cc", 0}; + +/* + * Drive the whole formatter by managing input files. Also, + * cause initialization of the output stuff and flush it out + * at the end. + */ + +main(argc, argv) + int argc; + char **argv; +{ + register FILE *fi; + register int errs = 0; + int number; /* LIZ@UOM 6/18/85 */ + + goal_length = GOAL_LENGTH; + max_length = MAX_LENGTH; + setout(); + lineno = 1; + mark = -10; + /* + * LIZ@UOM 6/18/85 -- Check for goal and max length arguments + */ + if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) { + argv++; + argc--; + goal_length = number; + if (argc > 1 && (1 == (sscanf(argv[1], "%d", &number)))) { + argv++; + argc--; + max_length = number; + } + } + if (max_length <= goal_length) { + fprintf(stderr, "Max length must be greater than %s\n", + "goal length"); + exit(1); + } + if (argc < 2) { + fmt(stdin); + oflush(); + exit(0); + } + while (--argc) { + if ((fi = fopen(*++argv, "r")) == NULL) { + perror(*argv); + errs++; + continue; + } + fmt(fi); + fclose(fi); + } + oflush(); + exit(errs); +} + +/* + * Read up characters from the passed input file, forming lines, + * doing ^H processing, expanding tabs, stripping trailing blanks, + * and sending each line down for analysis. + */ +fmt(fi) + FILE *fi; +{ + char linebuf[BUFSIZ], canonb[BUFSIZ]; + register char *cp, *cp2; + register int c, col; + + c = getc(fi); + while (c != EOF) { + /* + * Collect a line, doing ^H processing. + * Leave tabs for now. + */ + cp = linebuf; + while (c != '\n' && c != EOF && cp-linebuf < BUFSIZ-1) { + if (c == '\b') { + if (cp > linebuf) + cp--; + c = getc(fi); + continue; + } + if ((c < ' ' || c >= 0177) && c != '\t') { + c = getc(fi); + continue; + } + *cp++ = c; + c = getc(fi); + } + *cp = '\0'; + + /* + * Toss anything remaining on the input line. + */ + while (c != '\n' && c != EOF) + c = getc(fi); + + /* + * Expand tabs on the way to canonb. + */ + col = 0; + cp = linebuf; + cp2 = canonb; + while (c = *cp++) { + if (c != '\t') { + col++; + if (cp2-canonb < BUFSIZ-1) + *cp2++ = c; + continue; + } + do { + if (cp2-canonb < BUFSIZ-1) + *cp2++ = ' '; + col++; + } while ((col & 07) != 0); + } + + /* + * Swipe trailing blanks from the line. + */ + for (cp2--; cp2 >= canonb && *cp2 == ' '; cp2--) + ; + *++cp2 = '\0'; + prefix(canonb); + if (c != EOF) + c = getc(fi); + } +} + +/* + * Take a line devoid of tabs and other garbage and determine its + * blank prefix. If the indent changes, call for a linebreak. + * If the input line is blank, echo the blank line on the output. + * Finally, if the line minus the prefix is a mail header, try to keep + * it on a line by itself. + */ +prefix(line) + char line[]; +{ + register char *cp, **hp; + register int np, h; + + if (strlen(line) == 0) { + oflush(); + putchar('\n'); + return; + } + for (cp = line; *cp == ' '; cp++) + ; + np = cp - line; + + /* + * The following horrible expression attempts to avoid linebreaks + * when the indent changes due to a paragraph. + */ + if (np != pfx && (np > pfx || abs(pfx-np) > 8)) + oflush(); + if (h = ishead(cp)) + oflush(), mark = lineno; + if (lineno - mark < 3 && lineno - mark > 0) + for (hp = &headnames[0]; *hp != (char *) 0; hp++) + if (ispref(*hp, cp)) { + h = 1; + oflush(); + break; + } + if (!h && (h = (*cp == '.'))) + oflush(); + pfx = np; + if (h) + pack(cp, strlen(cp)); + else split(cp); + if (h) + oflush(); + lineno++; +} + +/* + * Split up the passed line into output "words" which are + * maximal strings of non-blanks with the blank separation + * attached at the end. Pass these words along to the output + * line packer. + */ +split(line) + char line[]; +{ + register char *cp, *cp2; + char word[BUFSIZ]; + int wordl; /* LIZ@UOM 6/18/85 */ + + cp = line; + while (*cp) { + cp2 = word; + wordl = 0; /* LIZ@UOM 6/18/85 */ + + /* + * Collect a 'word,' allowing it to contain escaped white + * space. + */ + while (*cp && *cp != ' ') { + if (*cp == '\\' && isspace(cp[1])) + *cp2++ = *cp++; + *cp2++ = *cp++; + wordl++;/* LIZ@UOM 6/18/85 */ + } + + /* + * Guarantee a space at end of line. Two spaces after end of + * sentence punctuation. + */ + if (*cp == '\0') { + *cp2++ = ' '; + if (index(".:!", cp[-1])) + *cp2++ = ' '; + } + while (*cp == ' ') + *cp2++ = *cp++; + *cp2 = '\0'; + /* + * LIZ@UOM 6/18/85 pack(word); + */ + pack(word, wordl); + } +} + +/* + * Output section. + * Build up line images from the words passed in. Prefix + * each line with correct number of blanks. The buffer "outbuf" + * contains the current partial line image, including prefixed blanks. + * "outp" points to the next available space therein. When outp is NOSTR, + * there ain't nothing in there yet. At the bottom of this whole mess, + * leading tabs are reinserted. + */ +char outbuf[BUFSIZ]; /* Sandbagged output line image */ +char *outp; /* Pointer in above */ + +/* + * Initialize the output section. + */ +setout() +{ + outp = NOSTR; +} + +/* + * Pack a word onto the output line. If this is the beginning of + * the line, push on the appropriately-sized string of blanks first. + * If the word won't fit on the current line, flush and begin a new + * line. If the word is too long to fit all by itself on a line, + * just give it its own and hope for the best. + * + * LIZ@UOM 6/18/85 -- If the new word will fit in at less than the + * goal length, take it. If not, then check to see if the line + * will be over the max length; if so put the word on the next + * line. If not, check to see if the line will be closer to the + * goal length with or without the word and take it or put it on + * the next line accordingly. + */ + +/* + * LIZ@UOM 6/18/85 -- pass in the length of the word as well + * pack(word) + * char word[]; + */ +pack(word,wl) + char word[]; + int wl; +{ + register char *cp; + register int s, t; + + if (outp == NOSTR) + leadin(); + /* + * LIZ@UOM 6/18/85 -- change condition to check goal_length; s is the + * length of the line before the word is added; t is now the length + * of the line after the word is added + * t = strlen(word); + * if (t+s <= LENGTH) + */ + s = outp - outbuf; + t = wl + s; + if ((t <= goal_length) || + ((t <= max_length) && (t - goal_length <= goal_length - s))) { + /* + * In like flint! + */ + for (cp = word; *cp; *outp++ = *cp++); + return; + } + if (s > pfx) { + oflush(); + leadin(); + } + for (cp = word; *cp; *outp++ = *cp++); +} + +/* + * If there is anything on the current output line, send it on + * its way. Set outp to NOSTR to indicate the absence of the current + * line prefix. + */ +oflush() +{ + if (outp == NOSTR) + return; + *outp = '\0'; + tabulate(outbuf); + outp = NOSTR; +} + +/* + * Take the passed line buffer, insert leading tabs where possible, and + * output on standard output (finally). + */ +tabulate(line) + char line[]; +{ + register char *cp; + register int b, t; + + /* + * Toss trailing blanks in the output line. + */ + cp = line + strlen(line) - 1; + while (cp >= line && *cp == ' ') + cp--; + *++cp = '\0'; + + /* + * Count the leading blank space and tabulate. + */ + for (cp = line; *cp == ' '; cp++) + ; + b = cp-line; + t = b >> 3; + b &= 07; + if (t > 0) + do + putc('\t', stdout); + while (--t); + if (b > 0) + do + putc(' ', stdout); + while (--b); + while (*cp) + putc(*cp++, stdout); + putc('\n', stdout); +} + +/* + * Initialize the output line with the appropriate number of + * leading blanks. + */ +leadin() +{ + register int b; + register char *cp; + + for (b = 0, cp = outbuf; b < pfx; b++) + *cp++ = ' '; + outp = cp; +} + +/* + * Save a string in dynamic space. + * This little goodie is needed for + * a headline detector in head.c + */ +char * +savestr(str) + char str[]; +{ + register char *top; + + top = malloc(strlen(str) + 1); + if (top == NOSTR) { + fprintf(stderr, "fmt: Ran out of memory\n"); + exit(1); + } + strcpy(top, str); + return (top); +} + +/* + * Is s1 a prefix of s2?? + */ +ispref(s1, s2) + register char *s1, *s2; +{ + + while (*s1++ == *s2) + ; + return (*s1 == '\0'); +} diff --git a/usr.bin/fold/Makefile b/usr.bin/fold/Makefile new file mode 100644 index 0000000..4d80007 --- /dev/null +++ b/usr.bin/fold/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fold + +.include diff --git a/usr.bin/fold/fold.1 b/usr.bin/fold/fold.1 new file mode 100644 index 0000000..1ebb523 --- /dev/null +++ b/usr.bin/fold/fold.1 @@ -0,0 +1,64 @@ +.\" 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. +.\" +.\" @(#)fold.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt FOLD 1 +.Os +.Sh NAME +.Nm fold +.Nd "fold long lines for finite width output device" +.Sh SYNOPSIS +.Nm fold +.Op Fl w Ar width +.Ar +.Sh DESCRIPTION +.Nm Fold +is a filter which folds the contents of the specified files, +or the standard input if no files are specified, +breaking the lines to have maximum of 80 characters. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl w +Specifies a line width to use instead of the default 80 characters. +.Ar Width +should be a multiple of 8 if tabs are present, or the tabs should +be expanded using +.Xr expand 1 +before using +.Nm fold . +.El +.Sh SEE ALSO +.Xr expand 1 +.Sh BUGS +If underlining is present it may be messed up by folding. diff --git a/usr.bin/fold/fold.c b/usr.bin/fold/fold.c new file mode 100644 index 0000000..983a492 --- /dev/null +++ b/usr.bin/fold/fold.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kevin Ruddy. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#define DEFLINEWIDTH 80 + +main(argc, argv) + int argc; + char **argv; +{ + extern int errno, optind; + extern char *optarg; + register int ch; + int width; + char *p; + + width = -1; + while ((ch = getopt(argc, argv, "0123456789w:")) != EOF) + switch (ch) { + case 'w': + if ((width = atoi(optarg)) <= 0) { + (void)fprintf(stderr, + "fold: illegal width value.\n"); + exit(1); + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (width == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + width = atoi(++p); + else + width = atoi(argv[optind] + 1); + } + break; + default: + (void)fprintf(stderr, + "usage: fold [-w width] [file ...]\n"); + exit(1); + } + argv += optind; + argc -= optind; + + if (width == -1) + width = DEFLINEWIDTH; + if (!*argv) + fold(width); + else for (; *argv; ++argv) + if (!freopen(*argv, "r", stdin)) { + (void)fprintf(stderr, + "fold: %s: %s\n", *argv, strerror(errno)); + exit(1); + } else + fold(width); + exit(0); +} + +fold(width) + register int width; +{ + register int ch, col, new; + + for (col = 0;;) { + switch (ch = getchar()) { + case EOF: + return; + case '\b': + new = col ? col - 1 : 0; + break; + case '\n': + case '\r': + new = 0; + break; + case '\t': + new = (col + 8) & ~7; + break; + default: + new = col + 1; + break; + } + + if (new > width) { + putchar('\n'); + col = 0; + } + putchar(ch); + + switch (ch) { + case '\b': + if (col > 0) + --col; + break; + case '\n': + case '\r': + col = 0; + break; + case '\t': + col += 8; + col &= ~7; + break; + default: + ++col; + break; + } + } +} diff --git a/usr.bin/fpr/Makefile b/usr.bin/fpr/Makefile new file mode 100644 index 0000000..b5d12f0 --- /dev/null +++ b/usr.bin/fpr/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fpr + +.include diff --git a/usr.bin/fpr/fpr.1 b/usr.bin/fpr/fpr.1 new file mode 100644 index 0000000..0234c48 --- /dev/null +++ b/usr.bin/fpr/fpr.1 @@ -0,0 +1,83 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Corbett. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)fpr.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt FPR 1 +.Os BSD 4.2 +.Sh NAME +.Nm fpr +.Nd print Fortran file +.Sh SYNOPSIS +.Nm fpr +.Sh DESCRIPTION +.Nm Fpr +is a filter that transforms files formatted according to +Fortran's carriage control conventions into files formatted +according to +.Ux +line printer conventions. +.Pp +.Nm Fpr +copies its input onto its output, replacing the carriage +control characters with characters that will produce the intended +effects when printed using +.Xr lpr 1 . +The first character of each line determines the vertical spacing as follows: +.Bd -ragged -offset indent -compact +.Bl -column Character +.It Blank One line +.It 0 Two lines +.It 1 To first line of next page +.It + No advance +.El +.Ed +.Pp +A blank line is treated as if its first +character is a blank. A blank that appears as a carriage control +character is deleted. A zero is changed to a newline. A one is +changed to a form feed. The effects of a "+" are simulated using +backspaces. +.Sh EXAMPLES +.Dl a.out \&| fpr \&| lpr +.Pp +.Dl fpr \&< f77.output \&| lpr +.Sh HISTORY +The +.Nm fpr +command +appeared in +.Bx 4.2 . +.Sh BUGS +Results are undefined for input lines longer than 170 characters. diff --git a/usr.bin/fpr/fpr.c b/usr.bin/fpr/fpr.c new file mode 100644 index 0000000..b8fdf9c --- /dev/null +++ b/usr.bin/fpr/fpr.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fpr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#define BLANK ' ' +#define TAB '\t' +#define NUL '\000' +#define FF '\f' +#define BS '\b' +#define CR '\r' +#define VTAB '\013' +#define EOL '\n' + +#define TRUE 1 +#define FALSE 0 + +#define MAXCOL 170 +#define TABSIZE 8 +#define INITWIDTH 8 + +typedef + struct column + { + int count; + int width; + char *str; + } + COLUMN; + +char cc; +char saved; +int length; +char *text; +int highcol; +COLUMN *line; +int maxpos; +int maxcol; + +extern char *malloc(); +extern char *calloc(); +extern char *realloc(); + + + +main() +{ + register int ch; + register char ateof; + register int i; + register int errorcount; + + + init(); + errorcount = 0; + ateof = FALSE; + + ch = getchar(); + if (ch == EOF) + exit(0); + + if (ch == EOL) + { + cc = NUL; + ungetc((int) EOL, stdin); + } + else if (ch == BLANK) + cc = NUL; + else if (ch == '1') + cc = FF; + else if (ch == '0') + cc = EOL; + else if (ch == '+') + cc = CR; + else + { + errorcount = 1; + cc = NUL; + ungetc(ch, stdin); + } + + while ( ! ateof) + { + gettext(); + ch = getchar(); + if (ch == EOF) + { + flush(); + ateof = TRUE; + } + else if (ch == EOL) + { + flush(); + cc = NUL; + ungetc((int) EOL, stdin); + } + else if (ch == BLANK) + { + flush(); + cc = NUL; + } + else if (ch == '1') + { + flush(); + cc = FF; + } + else if (ch == '0') + { + flush(); + cc = EOL; + } + else if (ch == '+') + { + for (i = 0; i < length; i++) + savech(i); + } + else + { + errorcount++; + flush(); + cc = NUL; + ungetc(ch, stdin); + } + } + + if (errorcount == 1) + fprintf(stderr, "Illegal carriage control - 1 line.\n"); + else if (errorcount > 1) + fprintf(stderr, "Illegal carriage control - %d lines.\n", errorcount); + + exit(0); +} + + + +init() +{ + register COLUMN *cp; + register COLUMN *cend; + register char *sp; + + + length = 0; + maxpos = MAXCOL; + sp = malloc((unsigned) maxpos); + if (sp == NULL) + nospace(); + text = sp; + + highcol = -1; + maxcol = MAXCOL; + line = (COLUMN *) calloc(maxcol, (unsigned) sizeof(COLUMN)); + if (line == NULL) + nospace(); + cp = line; + cend = line + (maxcol-1); + while (cp <= cend) + { + cp->width = INITWIDTH; + sp = calloc(INITWIDTH, (unsigned) sizeof(char)); + if (sp == NULL) + nospace(); + cp->str = sp; + cp++; + } +} + + + +gettext() +{ + register int i; + register char ateol; + register int ch; + register int pos; + + + i = 0; + ateol = FALSE; + + while ( ! ateol) + { + ch = getchar(); + if (ch == EOL || ch == EOF) + ateol = TRUE; + else if (ch == TAB) + { + pos = (1 + i/TABSIZE) * TABSIZE; + if (pos > maxpos) + { + maxpos = pos + 10; + text = realloc(text, (unsigned) maxpos); + if (text == NULL) + nospace(); + } + while (i < pos) + { + text[i] = BLANK; + i++; + } + } + else if (ch == BS) + { + if (i > 0) + { + i--; + savech(i); + } + } + else if (ch == CR) + { + while (i > 0) + { + i--; + savech(i); + } + } + else if (ch == FF || ch == VTAB) + { + flush(); + cc = ch; + i = 0; + } + else + { + if (i >= maxpos) + { + maxpos = i + 10; + text = realloc(text, (unsigned) maxpos); + if (text == NULL) + nospace(); + } + text[i] = ch; + i++; + } + } + + length = i; +} + + + +savech(col) +int col; +{ + register char ch; + register int oldmax; + register COLUMN *cp; + register COLUMN *cend; + register char *sp; + register int newcount; + + + ch = text[col]; + if (ch == BLANK) + return; + + saved = TRUE; + + if (col >= highcol) + highcol = col; + + if (col >= maxcol) + { + oldmax = maxcol; + maxcol = col + 10; + line = (COLUMN *) realloc(line, (unsigned) maxcol*sizeof(COLUMN)); + if (line == NULL) + nospace(); + cp = line + oldmax; + cend = line + (maxcol - 1); + while (cp <= cend) + { + cp->width = INITWIDTH; + cp->count = 0; + sp = calloc(INITWIDTH, (unsigned) sizeof(char)); + if (sp == NULL) + nospace(); + cp->str = sp; + cp++; + } + } + + cp = line + col; + newcount = cp->count + 1; + if (newcount > cp->width) + { + cp->width = newcount; + sp = realloc(cp->str, (unsigned) newcount*sizeof(char)); + if (sp == NULL) + nospace(); + cp->str = sp; + } + cp->count = newcount; + cp->str[newcount-1] = ch; +} + + + +flush() +{ + register int i; + register int anchor; + register int height; + register int j; + + + if (cc != NUL) + putchar(cc); + + if ( ! saved) + { + i = length; + while (i > 0 && text[i-1] == BLANK) + i--; + length = i; + for (i = 0; i < length; i++) + putchar(text[i]); + putchar(EOL); + return; + } + + for (i =0; i < length; i++) + savech(i); + + anchor = 0; + while (anchor <= highcol) + { + height = line[anchor].count; + if (height == 0) + { + putchar(BLANK); + anchor++; + } + else if (height == 1) + { + putchar( *(line[anchor].str) ); + line[anchor].count = 0; + anchor++; + } + else + { + i = anchor; + while (i < highcol && line[i+1].count > 1) + i++; + for (j = anchor; j <= i; j++) + { + height = line[j].count - 1; + putchar(line[j].str[height]); + line[j].count = height; + } + for (j = anchor; j <= i; j++) + putchar(BS); + } + } + + putchar(EOL); + highcol = -1; +} + + + +nospace() +{ + fputs("Storage limit exceeded.\n", stderr); + exit(1); +} diff --git a/usr.bin/from/Makefile b/usr.bin/from/Makefile new file mode 100644 index 0000000..a802dc6 --- /dev/null +++ b/usr.bin/from/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= from + +.include diff --git a/usr.bin/from/from.1 b/usr.bin/from/from.1 new file mode 100644 index 0000000..f935b89 --- /dev/null +++ b/usr.bin/from/from.1 @@ -0,0 +1,83 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (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.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt FROM 1 +.Os BSD 4 +.Sh NAME +.Nm from +.Nd print names of those who have sent mail +.Sh SYNOPSIS +.Nm from +.Op Fl s Ar sender +.Op Fl f Ar file +.Op Ar user +.Sh DESCRIPTION +.Nm From +prints +out the mail header lines from the invoker's mailbox. +.Pp +Options: +.Bl -tag -width Fl +.It Fl f Ar file +The supplied file +is examined instead of the invoker's mailbox. +If the +.Fl f +option is used, the +.Ar user +argument should not be used. +.It Fl s Ar sender +Only mail from addresses containing +the +supplied string are printed. +.El +.Pp +If +.Ar user +is given, the +.Ar user Ns 's +mailbox, is examined instead of the invoker's own mailbox. +(Privileges are required.) +.Sh FILES +.Bl -tag -width /var/mail/* -compact +.It Pa /var/mail/* +.El +.Sh SEE ALSO +.Xr biff 1 , +.Xr mail 1 +.Sh HISTORY +The +.Nm from +command appeared in +.Bx 3.0 . diff --git a/usr.bin/from/from.c b/usr.bin/from/from.c new file mode 100644 index 0000000..324bceb --- /dev/null +++ b/usr.bin/from/from.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1980, 1988, 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 copyright[] = +"@(#) Copyright (c) 1980, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)from.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + struct passwd *pwd; + int ch, newline; + char *file, *sender, *p; +#if MAXPATHLEN > BUFSIZ + char buf[MAXPATHLEN]; +#else + char buf[BUFSIZ]; +#endif + + file = sender = NULL; + while ((ch = getopt(argc, argv, "f:s:")) != EOF) + switch((char)ch) { + case 'f': + file = optarg; + break; + case 's': + sender = optarg; + for (p = sender; *p; ++p) + if (isupper(*p)) + *p = tolower(*p); + break; + case '?': + default: + fprintf(stderr, "usage: from [-f file] [-s sender] [user]\n"); + exit(1); + } + argv += optind; + + if (!file) { + if (!(file = *argv)) { + if (!(pwd = getpwuid(getuid()))) { + fprintf(stderr, + "from: no password file entry for you.\n"); + exit(1); + } + file = pwd->pw_name; + } + (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, file); + file = buf; + } + if (!freopen(file, "r", stdin)) { + fprintf(stderr, "from: can't read %s.\n", file); + exit(1); + } + for (newline = 1; fgets(buf, sizeof(buf), stdin);) { + if (*buf == '\n') { + newline = 1; + continue; + } + if (newline && !strncmp(buf, "From ", 5) && + (!sender || match(buf + 5, sender))) + printf("%s", buf); + newline = 0; + } + exit(0); +} + +match(line, sender) + register char *line, *sender; +{ + register char ch, pch, first, *p, *t; + + for (first = *sender++;;) { + if (isspace(ch = *line)) + return(0); + ++line; + if (isupper(ch)) + ch = tolower(ch); + if (ch != first) + continue; + for (p = sender, t = line;;) { + if (!(pch = *p++)) + return(1); + if (isupper(ch = *t++)) + ch = tolower(ch); + if (ch != pch) + break; + } + } + /* NOTREACHED */ +} diff --git a/usr.bin/fsplit/Makefile b/usr.bin/fsplit/Makefile new file mode 100644 index 0000000..f731a0d --- /dev/null +++ b/usr.bin/fsplit/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fsplit + +.include diff --git a/usr.bin/fsplit/fsplit.1 b/usr.bin/fsplit/fsplit.1 new file mode 100644 index 0000000..2494495 --- /dev/null +++ b/usr.bin/fsplit/fsplit.1 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Asa Romberger and Jerry Berkman. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)fsplit.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt FSPLIT 1 +.Os BSD 4.2 +.Sh NAME +.Nm fsplit +.Nd split a multi-routine Fortran file into individual files +.Sh SYNOPSIS +.Nm fsplit +.Op Fl e Ar efile +\&... +.Op Ar file +.Sh DESCRIPTION +.Nm Fsplit +takes as input either a file or standard input containing Fortran source code. +It attempts to split the input into separate routine files of the +form +.Ar name.f , +where +.Ar name +is the name of the program unit (e.g. function, subroutine, block data or +program). The name for unnamed block data subprograms has the form +.Ar blkdtaNNN.f +where NNN is three digits and a file of this name does not already exist. +For unnamed main programs the name has the form +.Ar mainNNN.f . +If there is an error in classifying a program unit, or if +.Ar name.f +already exists, +the program unit will be put in a file of the form +.Ar zzzNNN.f +where +.Ar zzzNNN.f +does not already exist. +.Pp +.Bl -tag -width Fl +.It Fl e Ar efile +Normally each subprogram unit is split into a separate file. When the +.Fl e +option is used, only the specified subprogram units are split into separate +files. E.g.: +.Pp +.Dl fsplit -e readit -e doit prog.f +.Pp +will split readit and doit into separate files. +.El +.Sh DIAGNOSTICS +If names specified via the +.Fl e +option are not found, a diagnostic is written to +standard error. +.Sh HISTORY +The +.Nm fsplit +command +appeared in +.Bx 4.2 . +.Sh AUTHORS +Asa Romberger and Jerry Berkman +.Sh BUGS +.Nm Fsplit +assumes the subprogram name is on the first noncomment line of the subprogram +unit. Nonstandard source formats may confuse +.Nm fsplit . +.Pp +It is hard to use +.Fl e +for unnamed main programs and block data subprograms since you must +predict the created file name. diff --git a/usr.bin/fsplit/fsplit.c b/usr.bin/fsplit/fsplit.c new file mode 100644 index 0000000..19cc965 --- /dev/null +++ b/usr.bin/fsplit/fsplit.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Asa Romberger and Jerry Berkman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fsplit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +/* + * usage: fsplit [-e efile] ... [file] + * + * split single file containing source for several fortran programs + * and/or subprograms into files each containing one + * subprogram unit. + * each separate file will be named using the corresponding subroutine, + * function, block data or program name if one is found; otherwise + * the name will be of the form mainNNN.f or blkdtaNNN.f . + * If a file of that name exists, it is saved in a name of the + * form zzz000.f . + * If -e option is used, then only those subprograms named in the -e + * option are split off; e.g.: + * fsplit -esub1 -e sub2 prog.f + * isolates sub1 and sub2 in sub1.f and sub2.f. The space + * after -e is optional. + * + * Modified Feb., 1983 by Jerry Berkman, Computing Services, U.C. Berkeley. + * - added comments + * - more function types: double complex, character*(*), etc. + * - fixed minor bugs + * - instead of all unnamed going into zNNN.f, put mains in + * mainNNN.f, block datas in blkdtaNNN.f, dups in zzzNNN.f . + */ + +#define BSZ 512 +char buf[BSZ]; +FILE *ifp; +char x[]="zzz000.f", + mainp[]="main000.f", + blkp[]="blkdta000.f"; +char *look(), *skiplab(), *functs(); + +#define TRUE 1 +#define FALSE 0 +int extr = FALSE, + extrknt = -1, + extrfnd[100]; +char extrbuf[1000], + *extrnames[100]; +struct stat sbuf; + +#define trim(p) while (*p == ' ' || *p == '\t') p++ + +main(argc, argv) +char **argv; +{ + register FILE *ofp; /* output file */ + register rv; /* 1 if got card in output file, 0 otherwise */ + register char *ptr; + int nflag, /* 1 if got name of subprog., 0 otherwise */ + retval, + i; + char name[20], + *extrptr = extrbuf; + + /* scan -e options */ + while ( argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') { + extr = TRUE; + ptr = argv[1] + 2; + if(!*ptr) { + argc--; + argv++; + if(argc <= 1) badparms(); + ptr = argv[1]; + } + extrknt = extrknt + 1; + extrnames[extrknt] = extrptr; + extrfnd[extrknt] = FALSE; + while(*ptr) *extrptr++ = *ptr++; + *extrptr++ = 0; + argc--; + argv++; + } + + if (argc > 2) + badparms(); + else if (argc == 2) { + if ((ifp = fopen(argv[1], "r")) == NULL) { + fprintf(stderr, "fsplit: cannot open %s\n", argv[1]); + exit(1); + } + } + else + ifp = stdin; + for(;;) { + /* look for a temp file that doesn't correspond to an existing file */ + get_name(x, 3); + ofp = fopen(x, "w"); + nflag = 0; + rv = 0; + while (getline() > 0) { + rv = 1; + fprintf(ofp, "%s", buf); + if (lend()) /* look for an 'end' statement */ + break; + if (nflag == 0) /* if no name yet, try and find one */ + nflag = lname(name); + } + fclose(ofp); + if (rv == 0) { /* no lines in file, forget the file */ + unlink(x); + retval = 0; + for ( i = 0; i <= extrknt; i++ ) + if(!extrfnd[i]) { + retval = 1; + fprintf( stderr, "fsplit: %s not found\n", + extrnames[i]); + } + exit( retval ); + } + if (nflag) { /* rename the file */ + if(saveit(name)) { + if (stat(name, &sbuf) < 0 ) { + link(x, name); + unlink(x); + printf("%s\n", name); + continue; + } else if (strcmp(name, x) == 0) { + printf("%s\n", x); + continue; + } + printf("%s already exists, put in %s\n", name, x); + continue; + } else + unlink(x); + continue; + } + if(!extr) + printf("%s\n", x); + else + unlink(x); + } +} + +badparms() +{ + fprintf(stderr, "fsplit: usage: fsplit [-e efile] ... [file] \n"); + exit(1); +} + +saveit(name) +char *name; +{ + int i; + char fname[50], + *fptr = fname; + + if(!extr) return(1); + while(*name) *fptr++ = *name++; + *--fptr = 0; + *--fptr = 0; + for ( i=0 ; i<=extrknt; i++ ) + if( strcmp(fname, extrnames[i]) == 0 ) { + extrfnd[i] = TRUE; + return(1); + } + return(0); +} + +get_name(name, letters) +char *name; +int letters; +{ + register char *ptr; + + while (stat(name, &sbuf) >= 0) { + for (ptr = name + letters + 2; ptr >= name + letters; ptr--) { + (*ptr)++; + if (*ptr <= '9') + break; + *ptr = '0'; + } + if(ptr < name + letters) { + fprintf( stderr, "fsplit: ran out of file names\n"); + exit(1); + } + } +} + +getline() +{ + register char *ptr; + + for (ptr = buf; ptr < &buf[BSZ]; ) { + *ptr = getc(ifp); + if (feof(ifp)) + return (-1); + if (*ptr++ == '\n') { + *ptr = 0; + return (1); + } + } + while (getc(ifp) != '\n' && feof(ifp) == 0) ; + fprintf(stderr, "line truncated to %d characters\n", BSZ); + return (1); +} + +/* return 1 for 'end' alone on card (up to col. 72), 0 otherwise */ +lend() +{ + register char *p; + + if ((p = skiplab(buf)) == 0) + return (0); + trim(p); + if (*p != 'e' && *p != 'E') return(0); + p++; + trim(p); + if (*p != 'n' && *p != 'N') return(0); + p++; + trim(p); + if (*p != 'd' && *p != 'D') return(0); + p++; + trim(p); + if (p - buf >= 72 || *p == '\n') + return (1); + return (0); +} + +/* check for keywords for subprograms + return 0 if comment card, 1 if found + name and put in arg string. invent name for unnamed + block datas and main programs. */ +lname(s) +char *s; +{ +# define LINESIZE 80 + register char *ptr, *p, *sptr; + char line[LINESIZE], *iptr = line; + + /* first check for comment cards */ + if(buf[0] == 'c' || buf[0] == 'C' || buf[0] == '*') return(0); + ptr = buf; + while (*ptr == ' ' || *ptr == '\t') ptr++; + if(*ptr == '\n') return(0); + + + ptr = skiplab(buf); + if (ptr == 0) + return (0); + + + /* copy to buffer and converting to lower case */ + p = ptr; + while (*p && p <= &buf[71] ) { + *iptr = isupper(*p) ? tolower(*p) : *p; + iptr++; + p++; + } + *iptr = '\n'; + + if ((ptr = look(line, "subroutine")) != 0 || + (ptr = look(line, "function")) != 0 || + (ptr = functs(line)) != 0) { + if(scan_name(s, ptr)) return(1); + strcpy( s, x); + } else if((ptr = look(line, "program")) != 0) { + if(scan_name(s, ptr)) return(1); + get_name( mainp, 4); + strcpy( s, mainp); + } else if((ptr = look(line, "blockdata")) != 0) { + if(scan_name(s, ptr)) return(1); + get_name( blkp, 6); + strcpy( s, blkp); + } else if((ptr = functs(line)) != 0) { + if(scan_name(s, ptr)) return(1); + strcpy( s, x); + } else { + get_name( mainp, 4); + strcpy( s, mainp); + } + return(1); +} + +scan_name(s, ptr) +char *s, *ptr; +{ + char *sptr; + + /* scan off the name */ + trim(ptr); + sptr = s; + while (*ptr != '(' && *ptr != '\n') { + if (*ptr != ' ' && *ptr != '\t') + *sptr++ = *ptr; + ptr++; + } + + if (sptr == s) return(0); + + *sptr++ = '.'; + *sptr++ = 'f'; + *sptr++ = 0; + return(1); +} + +char *functs(p) +char *p; +{ + register char *ptr; + +/* look for typed functions such as: real*8 function, + character*16 function, character*(*) function */ + + if((ptr = look(p,"character")) != 0 || + (ptr = look(p,"logical")) != 0 || + (ptr = look(p,"real")) != 0 || + (ptr = look(p,"integer")) != 0 || + (ptr = look(p,"doubleprecision")) != 0 || + (ptr = look(p,"complex")) != 0 || + (ptr = look(p,"doublecomplex")) != 0 ) { + while ( *ptr == ' ' || *ptr == '\t' || *ptr == '*' + || (*ptr >= '0' && *ptr <= '9') + || *ptr == '(' || *ptr == ')') ptr++; + ptr = look(ptr,"function"); + return(ptr); + } + else + return(0); +} + +/* if first 6 col. blank, return ptr to col. 7, + if blanks and then tab, return ptr after tab, + else return 0 (labelled statement, comment or continuation */ +char *skiplab(p) +char *p; +{ + register char *ptr; + + for (ptr = p; ptr < &p[6]; ptr++) { + if (*ptr == ' ') + continue; + if (*ptr == '\t') { + ptr++; + break; + } + return (0); + } + return (ptr); +} + +/* return 0 if m doesn't match initial part of s; + otherwise return ptr to next char after m in s */ +char *look(s, m) +char *s, *m; +{ + register char *sp, *mp; + + sp = s; mp = m; + while (*mp) { + trim(sp); + if (*sp++ != *mp++) + return (0); + } + return (sp); +} diff --git a/usr.bin/fstat/Makefile b/usr.bin/fstat/Makefile new file mode 100644 index 0000000..a8b50c2 --- /dev/null +++ b/usr.bin/fstat/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= fstat +CFLAGS+=-I/sys +DPADD= ${LIBKVM} +LDADD= -lkvm +BINGRP= kmem +BINMODE=2555 + +.include diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1 new file mode 100644 index 0000000..1db0330 --- /dev/null +++ b/usr.bin/fstat/fstat.1 @@ -0,0 +1,219 @@ +.\" Copyright (c) 1987, 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. +.\" +.\" @(#)fstat.1 8.3 (Berkeley) 2/25/94 +.\" +.Dd February 25, 1994 +.Dt FSTAT 1 +.Os BSD 4 +.Sh NAME +.Nm fstat +.Nd file status +.Sh SYNOPSIS +.Nm fstat +.Op Fl fnv +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl p Ar pid +.Op Fl u Ar user +.Op Ar filename... +.Sh DESCRIPTION +.Nm Fstat +identifies open files. +A file is considered open by a process if it was explicitly opened, +is the working directory, root directory, active pure text, or kernel +trace file for that process. +If no options are specified, +.Nm fstat +reports on all open files in the system. +.Pp +Options: +.Bl -tag -width Ds +.It Fl f +Restrict examination to files open in the same filesystems as +the named file arguments, or to the filesystem containing the +current directory if there are no additional filename arguments. +For example, to find all files open in the filesystem where the +directory +.Pa /usr/src +resides, type +.Dq Li fstat -f /usr/src . +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl N +Extract the name list from the specified system instead of the default +.Pa /vmunix . +.It Fl n +Numerical format. Print the device number (maj,min) of the filesystem +the file resides in rather than the mount point name; for special +files, print the +device number that the special device refers to rather than the filename +in +.Pa /dev ; +and print the mode of the file in octal instead of symbolic form. +.It Fl p +Report all files open by the specified process. +.It Fl u +Report all files open by the specified user. +.It Fl v +Verbose mode. Print error messages upon failures to locate particular +system data structures rather than silently ignoring them. Most of +these data structures are dynamically created or deleted and it is +possible for them to disappear while +.Nm fstat +is running. This +is normal and unavoidable since the rest of the system is running while +.Nm fstat +itself is running. +.It Ar filename ... +Restrict reports to the specified files. +.El +.Pp +The following fields are printed: +.Bl -tag -width MOUNT +.It Li USER +The username of the owner of the process (effective uid). +.It Li CMD +The command name of the process. +.It Li PID +The process id. +.It Li FD +The file number in the per-process open file table or one of the following +special names: +.Pp +.Bd -ragged -offset indent -compact +text - pure text inode +wd - current working directory +root - root inode +tr - kernel trace file +.Ed +.Pp +If the file number is followed by an asterisk (``*''), the file is +not an inode, but rather a socket, +.Tn FIFO , +or there is an error. +In this case the remainder of the line doesn't +correspond to the remaining headers -- the format of the line +is described later under +.Sx Sockets . +.It Li MOUNT +If the +.Fl n +flag wasn't specified, this header is present and is the +pathname that the filesystem the file resides in is mounted on. +.It Li DEV +If the +.Fl n +flag is specified, this header is present and is the +major/minor number of the device that this file resides in. +.It Li INUM +The inode number of the file. +.It Li MODE +The mode of the file. If the +.Fl n +flag isn't specified, the mode is printed +using a symbolic format (see +.Xr strmode 3 ) ; +otherwise, the mode is printed +as an octal number. +.It Li SZ\&|DV +If the file is not a character or block special, prints the size of +the file in bytes. Otherwise, if the +.Fl n +flag is not specified, prints +the name of the special file as located in +.Pa /dev . +If that cannot be +located, or the +.Fl n +flag is specified, prints the major/minor device +number that the special device refers to. +.It Li R/W +This column describes the access mode that the file allows. +The letter ``r'' indicates open for reading; +the letter ``w'' indicates open for writing. +This field is useful when trying to find the processes that are +preventing a filesystem from being down graded to read-only. +.It Li NAME +If filename arguments are specified and the +.Fl f +flag is not, then +this field is present and is the name associated with the given file. +Normally the name cannot be determined since there is no mapping +from an open file back to the directory entry that was used to open +that file. Also, since different directory entries may reference +the same file (via +.Xr ln 2 ) , +the name printed may not be the actual +name that the process originally used to open that file. +.El +.Sh SOCKETS +The formating of open sockets depends on the protocol domain. +In all cases the first field is the domain name, the second field +is the socket type (stream, dgram, etc), and the third is the socket +flags field (in hex). +The remaining fields are protocol dependent. +For tcp, it is the address of the tcpcb, and for udp, the inpcb (socket pcb). +For unix domain sockets, its the address of the socket pcb and the address +of the connected pcb (if connected). +Otherwise the protocol number and address of the socket itself are printed. +The attempt is to make enough information available to +permit further analysis without duplicating +.Xr netstat 1 . +.Pp +For example, the addresses mentioned above are the addresses which the +.Dq Li netstat -A +command would print for tcp, udp, and unixdomain. +Note that since pipes are implemented using sockets, a pipe appears as a +connected unix domain stream socket. +A unidirectional unix domain socket indicates the direction of flow with +an arrow (``<-'' or ``->''), and a full duplex socket shows a double arrow +(``<->''). +.Sh BUGS +Since +.Nm fstat +takes a snapshot of the system, it is only correct for a very short period +of time. +.Sh SEE ALSO +.Xr netstat 1 , +.Xr nfsstat 1 , +.Xr ps 1 , +.Xr systat 1 , +.Xr vmstat 1 , +.Xr iostat 8 , +.Xr pstat 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 tahoe . diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c new file mode 100644 index 0000000..90d7304 --- /dev/null +++ b/usr.bin/fstat/fstat.c @@ -0,0 +1,746 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)fstat.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define KERNEL +#include +#include +#include +#undef KERNEL +#define NFS +#include +#include +#include +#include +#include +#undef NFS + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEXT -1 +#define CDIR -2 +#define RDIR -3 +#define TRACE -4 + +typedef struct devs { + struct devs *next; + long fsid; + ino_t ino; + char *name; +} DEVS; +DEVS *devs; + +struct filestat { + long fsid; + long fileid; + mode_t mode; + u_long size; + dev_t rdev; +}; + +#ifdef notdef +struct nlist nl[] = { + { "" }, +}; +#endif + +int fsflg, /* show files on same filesystem as file(s) argument */ + pflg, /* show files open by a particular pid */ + uflg; /* show files open by a particular (effective) user */ +int checkfile; /* true if restricting to particular files or filesystems */ +int nflg; /* (numerical) display f.s. and rdev as dev_t */ +int vflg; /* display errors in locating kernel data objects etc... */ + +#define dprintf if (vflg) fprintf + +struct file **ofiles; /* buffer of pointers to file structures */ +int maxfiles; +#define ALLOC_OFILES(d) \ + if ((d) > maxfiles) { \ + free(ofiles); \ + ofiles = malloc((d) * sizeof(struct file *)); \ + if (ofiles == NULL) { \ + fprintf(stderr, "fstat: %s\n", strerror(errno)); \ + exit(1); \ + } \ + maxfiles = (d); \ + } + +/* + * a kvm_read that returns true if everything is read + */ +#define KVM_READ(kaddr, paddr, len) \ + (kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len)) + +kvm_t *kd; + +int ufs_filestat(), nfs_filestat(); +void dofiles(), getinetproto(), socktrans(); +void usage(), vtrans(); + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + register struct passwd *passwd; + struct kinfo_proc *p, *plast; + int arg, ch, what; + char *memf, *nlistf; + int cnt; + + arg = 0; + what = KERN_PROC_ALL; + nlistf = memf = NULL; + while ((ch = getopt(argc, argv, "fnp:u:vNM")) != EOF) + switch((char)ch) { + case 'f': + fsflg = 1; + break; + case 'M': + memf = optarg; + break; + case 'N': + nlistf = optarg; + break; + case 'n': + nflg = 1; + break; + case 'p': + if (pflg++) + usage(); + if (!isdigit(*optarg)) { + fprintf(stderr, + "fstat: -p requires a process id\n"); + usage(); + } + what = KERN_PROC_PID; + arg = atoi(optarg); + break; + case 'u': + if (uflg++) + usage(); + if (!(passwd = getpwnam(optarg))) { + fprintf(stderr, "%s: unknown uid\n", + optarg); + exit(1); + } + what = KERN_PROC_UID; + arg = passwd->pw_uid; + break; + case 'v': + vflg = 1; + break; + case '?': + default: + usage(); + } + + if (*(argv += optind)) { + for (; *argv; ++argv) { + if (getfname(*argv)) + checkfile = 1; + } + if (!checkfile) /* file(s) specified, but none accessable */ + exit(1); + } + + ALLOC_OFILES(256); /* reserve space for file pointers */ + + if (fsflg && !checkfile) { + /* -f with no files means use wd */ + if (getfname(".") == 0) + exit(1); + checkfile = 1; + } + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + if ((kd = kvm_open(nlistf, memf, NULL, O_RDONLY, NULL)) == NULL) { + fprintf(stderr, "fstat: %s\n", kvm_geterr(kd)); + exit(1); + } +#ifdef notdef + if (kvm_nlist(kd, nl) != 0) { + fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr(kd)); + exit(1); + } +#endif + if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) { + fprintf(stderr, "fstat: %s\n", kvm_geterr(kd)); + exit(1); + } + if (nflg) + printf("%s", +"USER CMD PID FD DEV INUM MODE SZ|DV R/W"); + else + printf("%s", +"USER CMD PID FD MOUNT INUM MODE SZ|DV R/W"); + if (checkfile && fsflg == 0) + printf(" NAME\n"); + else + putchar('\n'); + + for (plast = &p[cnt]; p < plast; ++p) { + if (p->kp_proc.p_stat == SZOMB) + continue; + dofiles(p); + } + exit(0); +} + +char *Uname, *Comm; +int Pid; + +#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \ + switch(i) { \ + case TEXT: \ + printf(" text"); \ + break; \ + case CDIR: \ + printf(" wd"); \ + break; \ + case RDIR: \ + printf(" root"); \ + break; \ + case TRACE: \ + printf(" tr"); \ + break; \ + default: \ + printf(" %4d", i); \ + break; \ + } + +/* + * print open files attributed to this process + */ +void +dofiles(kp) + struct kinfo_proc *kp; +{ + int i, last; + struct file file; + struct filedesc0 filed0; +#define filed filed0.fd_fd + struct proc *p = &kp->kp_proc; + struct eproc *ep = &kp->kp_eproc; + + extern char *user_from_uid(); + + Uname = user_from_uid(ep->e_ucred.cr_uid, 0); + Pid = p->p_pid; + Comm = p->p_comm; + + if (p->p_fd == NULL) + return; + if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) { + dprintf(stderr, "can't read filedesc at %x for pid %d\n", + p->p_fd, Pid); + return; + } + /* + * root directory vnode, if one + */ + if (filed.fd_rdir) + vtrans(filed.fd_rdir, RDIR, FREAD); + /* + * current working directory vnode + */ + vtrans(filed.fd_cdir, CDIR, FREAD); + /* + * ktrace vnode, if one + */ + if (p->p_tracep) + vtrans(p->p_tracep, TRACE, FREAD|FWRITE); + /* + * open files + */ +#define FPSIZE (sizeof (struct file *)) + ALLOC_OFILES(filed.fd_lastfile+1); + if (filed.fd_nfiles > NDFILE) { + if (!KVM_READ(filed.fd_ofiles, ofiles, + (filed.fd_lastfile+1) * FPSIZE)) { + dprintf(stderr, + "can't read file structures at %x for pid %d\n", + filed.fd_ofiles, Pid); + return; + } + } else + bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE); + for (i = 0; i <= filed.fd_lastfile; i++) { + if (ofiles[i] == NULL) + continue; + if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) { + dprintf(stderr, "can't read file %d at %x for pid %d\n", + i, ofiles[i], Pid); + continue; + } + if (file.f_type == DTYPE_VNODE) + vtrans((struct vnode *)file.f_data, i, file.f_flag); + else if (file.f_type == DTYPE_SOCKET) { + if (checkfile == 0) + socktrans((struct socket *)file.f_data, i); + } + else { + dprintf(stderr, + "unknown file type %d for file %d of pid %d\n", + file.f_type, i, Pid); + } + } +} + +void +vtrans(vp, i, flag) + struct vnode *vp; + int i; + int flag; +{ + struct vnode vn; + struct filestat fst; + char rw[3], mode[15]; + char *badtype = NULL, *filename, *getmnton(); + + filename = badtype = NULL; + if (!KVM_READ(vp, &vn, sizeof (struct vnode))) { + dprintf(stderr, "can't read vnode at %x for pid %d\n", + vp, Pid); + return; + } + if (vn.v_type == VNON || vn.v_tag == VT_NON) + badtype = "none"; + else if (vn.v_type == VBAD) + badtype = "bad"; + else + switch (vn.v_tag) { + case VT_UFS: + if (!ufs_filestat(&vn, &fst)) + badtype = "error"; + break; + case VT_MFS: + if (!ufs_filestat(&vn, &fst)) + badtype = "error"; + break; + case VT_NFS: + if (!nfs_filestat(&vn, &fst)) + badtype = "error"; + break; + default: { + static char unknown[10]; + sprintf(badtype = unknown, "?(%x)", vn.v_tag); + break;; + } + } + if (checkfile) { + int fsmatch = 0; + register DEVS *d; + + if (badtype) + return; + for (d = devs; d != NULL; d = d->next) + if (d->fsid == fst.fsid) { + fsmatch = 1; + if (d->ino == fst.fileid) { + filename = d->name; + break; + } + } + if (fsmatch == 0 || (filename == NULL && fsflg == 0)) + return; + } + PREFIX(i); + if (badtype) { + (void)printf(" - - %10s -\n", badtype); + return; + } + if (nflg) + (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid)); + else + (void)printf(" %-8s", getmnton(vn.v_mount)); + if (nflg) + (void)sprintf(mode, "%o", fst.mode); + else + strmode(fst.mode, mode); + (void)printf(" %6d %10s", fst.fileid, mode); + switch (vn.v_type) { + case VBLK: + case VCHR: { + char *name; + + if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ? + S_IFCHR : S_IFBLK)) == NULL)) + printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev)); + else + printf(" %6s", name); + break; + } + default: + printf(" %6d", fst.size); + } + rw[0] = '\0'; + if (flag & FREAD) + strcat(rw, "r"); + if (flag & FWRITE) + strcat(rw, "w"); + printf(" %2s", rw); + if (filename && !fsflg) + printf(" %s", filename); + putchar('\n'); +} + +int +ufs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct inode inode; + + if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) { + dprintf(stderr, "can't read inode at %x for pid %d\n", + VTOI(vp), Pid); + return 0; + } + fsp->fsid = inode.i_dev & 0xffff; + fsp->fileid = (long)inode.i_number; + fsp->mode = (mode_t)inode.i_mode; + fsp->size = (u_long)inode.i_size; + fsp->rdev = inode.i_rdev; + + return 1; +} + +int +nfs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct nfsnode nfsnode; + register mode_t mode; + + if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) { + dprintf(stderr, "can't read nfsnode at %x for pid %d\n", + VTONFS(vp), Pid); + return 0; + } + fsp->fsid = nfsnode.n_vattr.va_fsid; + fsp->fileid = nfsnode.n_vattr.va_fileid; + fsp->size = nfsnode.n_size; + fsp->rdev = nfsnode.n_vattr.va_rdev; + mode = (mode_t)nfsnode.n_vattr.va_mode; + switch (vp->v_type) { + case VREG: + mode |= S_IFREG; + break; + case VDIR: + mode |= S_IFDIR; + break; + case VBLK: + mode |= S_IFBLK; + break; + case VCHR: + mode |= S_IFCHR; + break; + case VLNK: + mode |= S_IFLNK; + break; + case VSOCK: + mode |= S_IFSOCK; + break; + case VFIFO: + mode |= S_IFIFO; + break; + }; + fsp->mode = mode; + + return 1; +} + + +char * +getmnton(m) + struct mount *m; +{ + static struct mount mount; + static struct mtab { + struct mtab *next; + struct mount *m; + char mntonname[MNAMELEN]; + } *mhead = NULL; + register struct mtab *mt; + + for (mt = mhead; mt != NULL; mt = mt->next) + if (m == mt->m) + return (mt->mntonname); + if (!KVM_READ(m, &mount, sizeof(struct mount))) { + fprintf(stderr, "can't read mount table at %x\n", m); + return (NULL); + } + if ((mt = malloc(sizeof (struct mtab))) == NULL) { + fprintf(stderr, "fstat: %s\n", strerror(errno)); + exit(1); + } + mt->m = m; + bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); + mt->next = mhead; + mhead = mt; + return (mt->mntonname); +} + +void +socktrans(sock, i) + struct socket *sock; + int i; +{ + static char *stypename[] = { + "unused", /* 0 */ + "stream", /* 1 */ + "dgram", /* 2 */ + "raw", /* 3 */ + "rdm", /* 4 */ + "seqpak" /* 5 */ + }; +#define STYPEMAX 5 + struct socket so; + struct protosw proto; + struct domain dom; + struct inpcb inpcb; + struct unpcb unpcb; + int len; + char dname[32], *strcpy(); + + PREFIX(i); + + /* fill in socket */ + if (!KVM_READ(sock, &so, sizeof(struct socket))) { + dprintf(stderr, "can't read sock at %x\n", sock); + goto bad; + } + + /* fill in protosw entry */ + if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) { + dprintf(stderr, "can't read protosw at %x", so.so_proto); + goto bad; + } + + /* fill in domain */ + if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) { + dprintf(stderr, "can't read domain at %x\n", proto.pr_domain); + goto bad; + } + + if ((len = kvm_read(kd, (u_long)dom.dom_name, dname, + sizeof(dname) - 1)) < 0) { + dprintf(stderr, "can't read domain name at %x\n", + dom.dom_name); + dname[0] = '\0'; + } + else + dname[len] = '\0'; + + if ((u_short)so.so_type > STYPEMAX) + printf("* %s ?%d", dname, so.so_type); + else + printf("* %s %s", dname, stypename[so.so_type]); + + /* + * protocol specific formatting + * + * Try to find interesting things to print. For tcp, the interesting + * thing is the address of the tcpcb, for udp and others, just the + * inpcb (socket pcb). For unix domain, its the address of the socket + * pcb and the address of the connected pcb (if connected). Otherwise + * just print the protocol number and address of the socket itself. + * The idea is not to duplicate netstat, but to make available enough + * information for further analysis. + */ + switch(dom.dom_family) { + case AF_INET: + getinetproto(proto.pr_protocol); + if (proto.pr_protocol == IPPROTO_TCP ) { + if (so.so_pcb) { + if (kvm_read(kd, (u_long)so.so_pcb, + (char *)&inpcb, sizeof(struct inpcb)) + != sizeof(struct inpcb)) { + dprintf(stderr, + "can't read inpcb at %x\n", + so.so_pcb); + goto bad; + } + printf(" %x", (int)inpcb.inp_ppcb); + } + } + else if (so.so_pcb) + printf(" %x", (int)so.so_pcb); + break; + case AF_UNIX: + /* print address of pcb and connected pcb */ + if (so.so_pcb) { + printf(" %x", (int)so.so_pcb); + if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb, + sizeof(struct unpcb)) != sizeof(struct unpcb)){ + dprintf(stderr, "can't read unpcb at %x\n", + so.so_pcb); + goto bad; + } + if (unpcb.unp_conn) { + char shoconn[4], *cp; + + cp = shoconn; + if (!(so.so_state & SS_CANTRCVMORE)) + *cp++ = '<'; + *cp++ = '-'; + if (!(so.so_state & SS_CANTSENDMORE)) + *cp++ = '>'; + *cp = '\0'; + printf(" %s %x", shoconn, + (int)unpcb.unp_conn); + } + } + break; + default: + /* print protocol number and socket address */ + printf(" %d %x", proto.pr_protocol, (int)sock); + } + printf("\n"); + return; +bad: + printf("* error\n"); +} + +/* + * getinetproto -- + * print name of protocol number + */ +void +getinetproto(number) + int number; +{ + char *cp; + + switch(number) { + case IPPROTO_IP: + cp = "ip"; break; + case IPPROTO_ICMP: + cp ="icmp"; break; + case IPPROTO_GGP: + cp ="ggp"; break; + case IPPROTO_TCP: + cp ="tcp"; break; + case IPPROTO_EGP: + cp ="egp"; break; + case IPPROTO_PUP: + cp ="pup"; break; + case IPPROTO_UDP: + cp ="udp"; break; + case IPPROTO_IDP: + cp ="idp"; break; + case IPPROTO_RAW: + cp ="raw"; break; + default: + printf(" %d", number); + return; + } + printf(" %s", cp); +} + +getfname(filename) + char *filename; +{ + struct stat statbuf; + DEVS *cur; + + if (stat(filename, &statbuf)) { + fprintf(stderr, "fstat: %s: %s\n", filename, strerror(errno)); + return(0); + } + if ((cur = malloc(sizeof(DEVS))) == NULL) { + fprintf(stderr, "fstat: %s\n", strerror(errno)); + exit(1); + } + cur->next = devs; + devs = cur; + + cur->ino = statbuf.st_ino; + cur->fsid = statbuf.st_dev & 0xffff; + cur->name = filename; + return(1); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile new file mode 100644 index 0000000..fbb5a91 --- /dev/null +++ b/usr.bin/ftp/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.2 (Berkeley) 4/3/94 + +PROG= ftp +SRCS= cmds.c cmdtab.c ftp.c main.c ruserpass.c domacro.c + +.include diff --git a/usr.bin/ftp/cmds.c b/usr.bin/ftp/cmds.c new file mode 100644 index 0000000..8da2b20 --- /dev/null +++ b/usr.bin/ftp/cmds.c @@ -0,0 +1,2206 @@ +/* + * Copyright (c) 1985, 1989, 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[] = "@(#)cmds.c 8.5 (Berkeley) 4/6/94"; +#endif /* not lint */ + +/* + * FTP User Program -- Command Routines. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" +#include "pathnames.h" + +jmp_buf jabort; +char *mname; +char *home = "/"; + +/* + * `Another' gets another argument, and stores the new argc and argv. + * It reverts to the top level (via main.c's intr()) on EOF/error. + * + * Returns false if no new arguments have been added. + */ +int +another(pargc, pargv, prompt) + int *pargc; + char ***pargv; + char *prompt; +{ + int len = strlen(line), ret; + + if (len >= sizeof(line) - 3) { + printf("sorry, arguments too long\n"); + intr(); + } + printf("(%s) ", prompt); + line[len++] = ' '; + if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) + intr(); + len += strlen(&line[len]); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + makeargv(); + ret = margc > *pargc; + *pargc = margc; + *pargv = margv; + return (ret); +} + +/* + * Connect to peer server and + * auto-login, if possible. + */ +void +setpeer(argc, argv) + int argc; + char *argv[]; +{ + char *host; + short port; + + if (connected) { + printf("Already connected to %s, use close first.\n", + hostname); + code = -1; + return; + } + if (argc < 2) + (void) another(&argc, &argv, "to"); + if (argc < 2 || argc > 3) { + printf("usage: %s host-name [port]\n", argv[0]); + code = -1; + return; + } + port = sp->s_port; + if (argc > 2) { + port = atoi(argv[2]); + if (port <= 0) { + printf("%s: bad port number-- %s\n", argv[1], argv[2]); + printf ("usage: %s host-name [port]\n", argv[0]); + code = -1; + return; + } + port = htons(port); + } + host = hookup(argv[1], port); + if (host) { + int overbose; + + connected = 1; + /* + * Set up defaults for FTP. + */ + (void) strcpy(typename, "ascii"), type = TYPE_A; + curtype = TYPE_A; + (void) strcpy(formname, "non-print"), form = FORM_N; + (void) strcpy(modename, "stream"), mode = MODE_S; + (void) strcpy(structname, "file"), stru = STRU_F; + (void) strcpy(bytename, "8"), bytesize = 8; + if (autologin) + (void) login(argv[1]); + +#if defined(unix) && NBBY == 8 +/* + * this ifdef is to keep someone form "porting" this to an incompatible + * system and not checking this out. This way they have to think about it. + */ + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("SYST") == COMPLETE && overbose) { + char *cp, c; + cp = strchr(reply_string+4, ' '); + if (cp == NULL) + cp = strchr(reply_string+4, '\r'); + if (cp) { + if (cp[-1] == '.') + cp--; + c = *cp; + *cp = '\0'; + } + + printf("Remote system type is %s.\n", + reply_string+4); + if (cp) + *cp = c; + } + if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { + if (proxy) + unix_proxy = 1; + else + unix_server = 1; + /* + * Set type to 0 (not specified by user), + * meaning binary by default, but don't bother + * telling server. We can use binary + * for text files unless changed by the user. + */ + type = 0; + (void) strcpy(typename, "binary"); + if (overbose) + printf("Using %s mode to transfer files.\n", + typename); + } else { + if (proxy) + unix_proxy = 0; + else + unix_server = 0; + if (overbose && + !strncmp(reply_string, "215 TOPS20", 10)) + printf( +"Remember to set tenex mode when transfering binary files from this machine.\n"); + } + verbose = overbose; +#endif /* unix */ + } +} + +struct types { + char *t_name; + char *t_mode; + int t_type; + char *t_arg; +} types[] = { + { "ascii", "A", TYPE_A, 0 }, + { "binary", "I", TYPE_I, 0 }, + { "image", "I", TYPE_I, 0 }, + { "ebcdic", "E", TYPE_E, 0 }, + { "tenex", "L", TYPE_L, bytename }, + { NULL } +}; + +/* + * Set transfer type. + */ +void +settype(argc, argv) + int argc; + char *argv[]; +{ + struct types *p; + int comret; + + if (argc > 2) { + char *sep; + + printf("usage: %s [", argv[0]); + sep = " "; + for (p = types; p->t_name; p++) { + printf("%s%s", sep, p->t_name); + sep = " | "; + } + printf(" ]\n"); + code = -1; + return; + } + if (argc < 2) { + printf("Using %s mode to transfer files.\n", typename); + code = 0; + return; + } + for (p = types; p->t_name; p++) + if (strcmp(argv[1], p->t_name) == 0) + break; + if (p->t_name == 0) { + printf("%s: unknown mode\n", argv[1]); + code = -1; + return; + } + if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) + comret = command ("TYPE %s %s", p->t_mode, p->t_arg); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) { + (void) strcpy(typename, p->t_name); + curtype = type = p->t_type; + } +} + +/* + * Internal form of settype; changes current type in use with server + * without changing our notion of the type for data transfers. + * Used to change to and from ascii for listings. + */ +void +changetype(newtype, show) + int newtype, show; +{ + struct types *p; + int comret, oldverbose = verbose; + + if (newtype == 0) + newtype = TYPE_I; + if (newtype == curtype) + return; + if (debug == 0 && show == 0) + verbose = 0; + for (p = types; p->t_name; p++) + if (newtype == p->t_type) + break; + if (p->t_name == 0) { + printf("ftp: internal error: unknown type %d\n", newtype); + return; + } + if (newtype == TYPE_L && bytename[0] != '\0') + comret = command("TYPE %s %s", p->t_mode, bytename); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) + curtype = newtype; + verbose = oldverbose; +} + +char *stype[] = { + "type", + "", + 0 +}; + +/* + * Set binary transfer type. + */ +/*VARARGS*/ +void +setbinary(argc, argv) + int argc; + char **argv; +{ + + stype[1] = "binary"; + settype(2, stype); +} + +/* + * Set ascii transfer type. + */ +/*VARARGS*/ +void +setascii(argc, argv) + int argc; + char *argv[]; +{ + + stype[1] = "ascii"; + settype(2, stype); +} + +/* + * Set tenex transfer type. + */ +/*VARARGS*/ +void +settenex(argc, argv) + int argc; + char *argv[]; +{ + + stype[1] = "tenex"; + settype(2, stype); +} + +/* + * Set file transfer mode. + */ +/*ARGSUSED*/ +void +setftmode(argc, argv) + int argc; + char *argv[]; +{ + + printf("We only support %s mode, sorry.\n", modename); + code = -1; +} + +/* + * Set file transfer format. + */ +/*ARGSUSED*/ +void +setform(argc, argv) + int argc; + char *argv[]; +{ + + printf("We only support %s format, sorry.\n", formname); + code = -1; +} + +/* + * Set file transfer structure. + */ +/*ARGSUSED*/ +void +setstruct(argc, argv) + int argc; + char *argv[]; +{ + + printf("We only support %s structure, sorry.\n", structname); + code = -1; +} + +/* + * Send a single file. + */ +void +put(argc, argv) + int argc; + char *argv[]; +{ + char *cmd; + int loc = 0; + char *oldargv1, *oldargv2; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + if (argc < 2 && !another(&argc, &argv, "local-file")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "remote-file")) { +usage: + printf("usage: %s local-file remote-file\n", argv[0]); + code = -1; + return; + } + oldargv1 = argv[1]; + oldargv2 = argv[2]; + if (!globulize(&argv[1])) { + code = -1; + return; + } + /* + * If "globulize" modifies argv[1], and argv[2] is a copy of + * the old argv[1], make it a copy of the new argv[1]. + */ + if (argv[1] != oldargv1 && argv[2] == oldargv1) { + argv[2] = argv[1]; + } + cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); + if (loc && ntflag) { + argv[2] = dotrans(argv[2]); + } + if (loc && mapflag) { + argv[2] = domap(argv[2]); + } + sendrequest(cmd, argv[1], argv[2], + argv[1] != oldargv1 || argv[2] != oldargv2); +} + +/* + * Send multiple files. + */ +void +mput(argc, argv) + int argc; + char **argv; +{ + int i; + sig_t oldintr; + int ointer; + char *tp; + + if (argc < 2 && !another(&argc, &argv, "local-files")) { + printf("usage: %s local-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + (void) setjmp(jabort); + if (proxy) { + char *cp, *tp2, tmpbuf[MAXPATHLEN]; + + while ((cp = remglob(argv,0)) != NULL) { + if (*cp == 0) { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + tp = cp; + if (mcase) { + while (*tp && !islower(*tp)) { + tp++; + } + if (!*tp) { + tp = cp; + tp2 = tmpbuf; + while ((*tp2 = *tp) != NULL) { + if (isupper(*tp2)) { + *tp2 = 'a' + *tp2 - 'A'; + } + tp++; + tp2++; + } + } + tp = tmpbuf; + } + if (ntflag) { + tp = dotrans(tp); + } + if (mapflag) { + tp = domap(tp); + } + sendrequest((sunique) ? "STOU" : "STOR", + cp, tp, cp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + } + (void) signal(SIGINT, oldintr); + mflag = 0; + return; + } + for (i = 1; i < argc; i++) { + char **cpp, **gargs; + glob_t gl; + int flags; + + if (!doglob) { + if (mflag && confirm(argv[0], argv[i])) { + tp = (ntflag) ? dotrans(argv[i]) : argv[i]; + tp = (mapflag) ? domap(tp) : tp; + sendrequest((sunique) ? "STOU" : "STOR", + argv[i], tp, tp != argv[i] || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + continue; + } + + memset(&gl, 0, sizeof(gl)); + flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; + if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { + warnx("%s: not found", argv[i]); + globfree(&gl); + continue; + } + for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { + if (mflag && confirm(argv[0], *cpp)) { + tp = (ntflag) ? dotrans(*cpp) : *cpp; + tp = (mapflag) ? domap(tp) : tp; + sendrequest((sunique) ? "STOU" : "STOR", + *cpp, tp, *cpp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + } + globfree(&gl); + } + (void) signal(SIGINT, oldintr); + mflag = 0; +} + +void +reget(argc, argv) + int argc; + char *argv[]; +{ + + (void) getit(argc, argv, 1, "r+w"); +} + +void +get(argc, argv) + int argc; + char *argv[]; +{ + + (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" ); +} + +/* + * Receive one file. + */ +int +getit(argc, argv, restartit, mode) + int argc; + char *argv[]; + char *mode; + int restartit; +{ + int loc = 0; + char *oldargv1, *oldargv2; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + if (argc < 2 && !another(&argc, &argv, "remote-file")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "local-file")) { +usage: + printf("usage: %s remote-file [ local-file ]\n", argv[0]); + code = -1; + return (0); + } + oldargv1 = argv[1]; + oldargv2 = argv[2]; + if (!globulize(&argv[2])) { + code = -1; + return (0); + } + if (loc && mcase) { + char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; + + while (*tp && !islower(*tp)) { + tp++; + } + if (!*tp) { + tp = argv[2]; + tp2 = tmpbuf; + while ((*tp2 = *tp) != NULL) { + if (isupper(*tp2)) { + *tp2 = 'a' + *tp2 - 'A'; + } + tp++; + tp2++; + } + argv[2] = tmpbuf; + } + } + if (loc && ntflag) + argv[2] = dotrans(argv[2]); + if (loc && mapflag) + argv[2] = domap(argv[2]); + if (restartit) { + struct stat stbuf; + int ret; + + ret = stat(argv[2], &stbuf); + if (restartit == 1) { + if (ret < 0) { + warn("local: %s", argv[2]); + return (0); + } + restart_point = stbuf.st_size; + } else { + if (ret == 0) { + int overbose; + + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("MDTM %s", argv[1]) == COMPLETE) { + int yy, mo, day, hour, min, sec; + struct tm *tm; + verbose = overbose; + sscanf(reply_string, + "%*s %04d%02d%02d%02d%02d%02d", + &yy, &mo, &day, &hour, &min, &sec); + tm = gmtime(&stbuf.st_mtime); + tm->tm_mon++; + if (tm->tm_year > yy%100) + return (1); + if ((tm->tm_year == yy%100 && + tm->tm_mon > mo) || + (tm->tm_mon == mo && + tm->tm_mday > day) || + (tm->tm_mday == day && + tm->tm_hour > hour) || + (tm->tm_hour == hour && + tm->tm_min > min) || + (tm->tm_min == min && + tm->tm_sec > sec)) + return (1); + } else { + printf("%s\n", reply_string); + verbose = overbose; + return (0); + } + } + } + } + + recvrequest("RETR", argv[2], argv[1], mode, + argv[1] != oldargv1 || argv[2] != oldargv2); + restart_point = 0; + return (0); +} + +/* ARGSUSED */ +void +mabort(signo) + int signo; +{ + int ointer; + + printf("\n"); + (void) fflush(stdout); + if (mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", mname)) { + interactive = ointer; + longjmp(jabort,0); + } + interactive = ointer; + } + mflag = 0; + longjmp(jabort,0); +} + +/* + * Get multiple files. + */ +void +mget(argc, argv) + int argc; + char **argv; +{ + sig_t oldintr; + int ch, ointer; + char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; + + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + (void) setjmp(jabort); + while ((cp = remglob(argv,proxy)) != NULL) { + if (*cp == '\0') { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + tp = cp; + if (mcase) { + for (tp2 = tmpbuf; ch = *tp++;) + *tp2++ = isupper(ch) ? tolower(ch) : ch; + tp = tmpbuf; + } + if (ntflag) { + tp = dotrans(tp); + } + if (mapflag) { + tp = domap(tp); + } + recvrequest("RETR", tp, cp, "w", + tp != cp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mget")) { + mflag++; + } + interactive = ointer; + } + } + } + (void) signal(SIGINT,oldintr); + mflag = 0; +} + +char * +remglob(argv,doswitch) + char *argv[]; + int doswitch; +{ + char temp[16]; + static char buf[MAXPATHLEN]; + static FILE *ftemp = NULL; + static char **args; + int oldverbose, oldhash; + char *cp, *mode; + + if (!mflag) { + if (!doglob) { + args = NULL; + } + else { + if (ftemp) { + (void) fclose(ftemp); + ftemp = NULL; + } + } + return (NULL); + } + if (!doglob) { + if (args == NULL) + args = argv; + if ((cp = *++args) == NULL) + args = NULL; + return (cp); + } + if (ftemp == NULL) { + (void) strcpy(temp, _PATH_TMP); + (void) mktemp(temp); + oldverbose = verbose, verbose = 0; + oldhash = hash, hash = 0; + if (doswitch) { + pswitch(!proxy); + } + for (mode = "w"; *++argv != NULL; mode = "a") + recvrequest ("NLST", temp, *argv, mode, 0); + if (doswitch) { + pswitch(!proxy); + } + verbose = oldverbose; hash = oldhash; + ftemp = fopen(temp, "r"); + (void) unlink(temp); + if (ftemp == NULL) { + printf("can't find list of remote files, oops\n"); + return (NULL); + } + } + if (fgets(buf, sizeof (buf), ftemp) == NULL) { + (void) fclose(ftemp), ftemp = NULL; + return (NULL); + } + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + return (buf); +} + +char * +onoff(bool) + int bool; +{ + + return (bool ? "on" : "off"); +} + +/* + * Show status. + */ +/*ARGSUSED*/ +void +status(argc, argv) + int argc; + char *argv[]; +{ + int i; + + if (connected) + printf("Connected to %s.\n", hostname); + else + printf("Not connected.\n"); + if (!proxy) { + pswitch(1); + if (connected) { + printf("Connected for proxy commands to %s.\n", hostname); + } + else { + printf("No proxy connection.\n"); + } + pswitch(0); + } + printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", + modename, typename, formname, structname); + printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", + onoff(verbose), onoff(bell), onoff(interactive), + onoff(doglob)); + printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), + onoff(runique)); + printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); + if (ntflag) { + printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); + } + else { + printf("Ntrans: off\n"); + } + if (mapflag) { + printf("Nmap: (in) %s (out) %s\n", mapin, mapout); + } + else { + printf("Nmap: off\n"); + } + printf("Hash mark printing: %s; Use of PORT cmds: %s\n", + onoff(hash), onoff(sendport)); + if (macnum > 0) { + printf("Macros:\n"); + for (i=0; i 1) { + val = atoi(argv[1]); + if (val < 0) { + printf("%s: bad debugging value.\n", argv[1]); + code = -1; + return; + } + } else + val = !debug; + debug = val; + if (debug) + options |= SO_DEBUG; + else + options &= ~SO_DEBUG; + printf("Debugging %s (debug=%d).\n", onoff(debug), debug); + code = debug > 0; +} + +/* + * Set current working directory + * on remote machine. + */ +void +cd(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "remote-directory")) { + printf("usage: %s remote-directory\n", argv[0]); + code = -1; + return; + } + if (command("CWD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("CWD command not recognized, trying XCWD\n"); + (void) command("XCWD %s", argv[1]); + } +} + +/* + * Set current working directory + * on local machine. + */ +void +lcd(argc, argv) + int argc; + char *argv[]; +{ + char buf[MAXPATHLEN]; + + if (argc < 2) + argc++, argv[1] = home; + if (argc != 2) { + printf("usage: %s local-directory\n", argv[0]); + code = -1; + return; + } + if (!globulize(&argv[1])) { + code = -1; + return; + } + if (chdir(argv[1]) < 0) { + warn("local: %s", argv[1]); + code = -1; + return; + } + if (getwd(buf) != NULL) + printf("Local directory now %s\n", buf); + else + warnx("getwd: %s", buf); + code = 0; +} + +/* + * Delete a single file. + */ +void +delete(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "remote-file")) { + printf("usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + (void) command("DELE %s", argv[1]); +} + +/* + * Delete multiple files. + */ +void +mdelete(argc, argv) + int argc; + char **argv; +{ + sig_t oldintr; + int ointer; + char *cp; + + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + (void) setjmp(jabort); + while ((cp = remglob(argv,0)) != NULL) { + if (*cp == '\0') { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + (void) command("DELE %s", cp); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mdelete")) { + mflag++; + } + interactive = ointer; + } + } + } + (void) signal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Rename a remote file. + */ +void +renamefile(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "from-name")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "to-name")) { +usage: + printf("%s from-name to-name\n", argv[0]); + code = -1; + return; + } + if (command("RNFR %s", argv[1]) == CONTINUE) + (void) command("RNTO %s", argv[2]); +} + +/* + * Get a directory listing + * of remote files. + */ +void +ls(argc, argv) + int argc; + char *argv[]; +{ + char *cmd; + + if (argc < 2) + argc++, argv[1] = NULL; + if (argc < 3) + argc++, argv[2] = "-"; + if (argc > 3) { + printf("usage: %s remote-directory local-file\n", argv[0]); + code = -1; + return; + } + cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; + if (strcmp(argv[2], "-") && !globulize(&argv[2])) { + code = -1; + return; + } + if (strcmp(argv[2], "-") && *argv[2] != '|') + if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { + code = -1; + return; + } + recvrequest(cmd, argv[2], argv[1], "w", 0); +} + +/* + * Get a directory listing + * of multiple remote files. + */ +void +mls(argc, argv) + int argc; + char **argv; +{ + sig_t oldintr; + int ointer, i; + char *cmd, mode[1], *dest; + + if (argc < 2 && !another(&argc, &argv, "remote-files")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "local-file")) { +usage: + printf("usage: %s remote-files local-file\n", argv[0]); + code = -1; + return; + } + dest = argv[argc - 1]; + argv[argc - 1] = NULL; + if (strcmp(dest, "-") && *dest != '|') + if (!globulize(&dest) || + !confirm("output to local-file:", dest)) { + code = -1; + return; + } + cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + (void) setjmp(jabort); + for (i = 1; mflag && i < argc-1; ++i) { + *mode = (i == 1) ? 'w' : 'a'; + recvrequest(cmd, dest, argv[i], mode, 0); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", argv[0])) { + mflag ++; + } + interactive = ointer; + } + } + (void) signal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Do a shell escape + */ +/*ARGSUSED*/ +void +shell(argc, argv) + int argc; + char **argv; +{ + pid_t pid; + sig_t old1, old2; + char shellnam[40], *shell, *namep; + union wait status; + + old1 = signal (SIGINT, SIG_IGN); + old2 = signal (SIGQUIT, SIG_IGN); + if ((pid = fork()) == 0) { + for (pid = 3; pid < 20; pid++) + (void) close(pid); + (void) signal(SIGINT, SIG_DFL); + (void) signal(SIGQUIT, SIG_DFL); + shell = getenv("SHELL"); + if (shell == NULL) + shell = _PATH_BSHELL; + namep = strrchr(shell,'/'); + if (namep == NULL) + namep = shell; + (void) strcpy(shellnam,"-"); + (void) strcat(shellnam, ++namep); + if (strcmp(namep, "sh") != 0) + shellnam[0] = '+'; + if (debug) { + printf ("%s\n", shell); + (void) fflush (stdout); + } + if (argc > 1) { + execl(shell,shellnam,"-c",altarg,(char *)0); + } + else { + execl(shell,shellnam,(char *)0); + } + warn("%s", shell); + code = -1; + exit(1); + } + if (pid > 0) + while (wait((int *)&status) != pid) + ; + (void) signal(SIGINT, old1); + (void) signal(SIGQUIT, old2); + if (pid == -1) { + warn("%s", "Try again later"); + code = -1; + } + else { + code = 0; + } +} + +/* + * Send new user information (re-login) + */ +void +user(argc, argv) + int argc; + char **argv; +{ + char acct[80]; + int n, aflag = 0; + + if (argc < 2) + (void) another(&argc, &argv, "username"); + if (argc < 2 || argc > 4) { + printf("usage: %s username [password] [account]\n", argv[0]); + code = -1; + return; + } + n = command("USER %s", argv[1]); + if (n == CONTINUE) { + if (argc < 3 ) + argv[2] = getpass("Password: "), argc++; + n = command("PASS %s", argv[2]); + } + if (n == CONTINUE) { + if (argc < 4) { + printf("Account: "); (void) fflush(stdout); + (void) fgets(acct, sizeof(acct) - 1, stdin); + acct[strlen(acct) - 1] = '\0'; + argv[3] = acct; argc++; + } + n = command("ACCT %s", argv[3]); + aflag++; + } + if (n != COMPLETE) { + fprintf(stdout, "Login failed.\n"); + return; + } + if (!aflag && argc == 4) { + (void) command("ACCT %s", argv[3]); + } +} + +/* + * Print working directory. + */ +/*VARARGS*/ +void +pwd(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + /* + * If we aren't verbose, this doesn't do anything! + */ + verbose = 1; + if (command("PWD") == ERROR && code == 500) { + printf("PWD command not recognized, trying XPWD\n"); + (void) command("XPWD"); + } + verbose = oldverbose; +} + +/* + * Make a directory. + */ +void +makedir(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "directory-name")) { + printf("usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + if (command("MKD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("MKD command not recognized, trying XMKD\n"); + (void) command("XMKD %s", argv[1]); + } +} + +/* + * Remove a directory. + */ +void +removedir(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "directory-name")) { + printf("usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + if (command("RMD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("RMD command not recognized, trying XRMD\n"); + (void) command("XRMD %s", argv[1]); + } +} + +/* + * Send a line, verbatim, to the remote machine. + */ +void +quote(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "command line to send")) { + printf("usage: %s line-to-send\n", argv[0]); + code = -1; + return; + } + quote1("", argc, argv); +} + +/* + * Send a SITE command to the remote machine. The line + * is sent verbatim to the remote machine, except that the + * word "SITE" is added at the front. + */ +void +site(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { + printf("usage: %s line-to-send\n", argv[0]); + code = -1; + return; + } + quote1("SITE ", argc, argv); +} + +/* + * Turn argv[1..argc) into a space-separated string, then prepend initial text. + * Send the result as a one-line command and get response. + */ +void +quote1(initial, argc, argv) + char *initial; + int argc; + char **argv; +{ + int i, len; + char buf[BUFSIZ]; /* must be >= sizeof(line) */ + + (void) strcpy(buf, initial); + if (argc > 1) { + len = strlen(buf); + len += strlen(strcpy(&buf[len], argv[1])); + for (i = 2; i < argc; i++) { + buf[len++] = ' '; + len += strlen(strcpy(&buf[len], argv[i])); + } + } + if (command(buf) == PRELIM) { + while (getreply(0) == PRELIM) + continue; + } +} + +void +do_chmod(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "mode")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "file-name")) { +usage: + printf("usage: %s mode file-name\n", argv[0]); + code = -1; + return; + } + (void) command("SITE CHMOD %s %s", argv[1], argv[2]); +} + +void +do_umask(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + verbose = 1; + (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); + verbose = oldverbose; +} + +void +idle(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + verbose = 1; + (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); + verbose = oldverbose; +} + +/* + * Ask the other side for help. + */ +void +rmthelp(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + verbose = 1; + (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); + verbose = oldverbose; +} + +/* + * Terminate session and exit. + */ +/*VARARGS*/ +void +quit(argc, argv) + int argc; + char *argv[]; +{ + + if (connected) + disconnect(0, 0); + pswitch(1); + if (connected) { + disconnect(0, 0); + } + exit(0); +} + +/* + * Terminate session, but don't exit. + */ +void +disconnect(argc, argv) + int argc; + char *argv[]; +{ + + if (!connected) + return; + (void) command("QUIT"); + if (cout) { + (void) fclose(cout); + } + cout = NULL; + connected = 0; + data = -1; + if (!proxy) { + macnum = 0; + } +} + +int +confirm(cmd, file) + char *cmd, *file; +{ + char line[BUFSIZ]; + + if (!interactive) + return (1); + printf("%s %s? ", cmd, file); + (void) fflush(stdout); + if (fgets(line, sizeof line, stdin) == NULL) + return (0); + return (*line != 'n' && *line != 'N'); +} + +void +fatal(msg) + char *msg; +{ + + errx(1, "%s", msg); +} + +/* + * Glob a local file name specification with + * the expectation of a single return value. + * Can't control multiple values being expanded + * from the expression, we return only the first. + */ +int +globulize(cpp) + char **cpp; +{ + glob_t gl; + int flags; + + if (!doglob) + return (1); + + flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; + memset(&gl, 0, sizeof(gl)); + if (glob(*cpp, flags, NULL, &gl) || + gl.gl_pathc == 0) { + warnx("%s: not found", *cpp); + globfree(&gl); + return (0); + } + *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */ + globfree(&gl); + return (1); +} + +void +account(argc,argv) + int argc; + char **argv; +{ + char acct[50], *ap; + + if (argc > 1) { + ++argv; + --argc; + (void) strncpy(acct,*argv,49); + acct[49] = '\0'; + while (argc > 1) { + --argc; + ++argv; + (void) strncat(acct,*argv, 49-strlen(acct)); + } + ap = acct; + } + else { + ap = getpass("Account:"); + } + (void) command("ACCT %s", ap); +} + +jmp_buf abortprox; + +void +proxabort() +{ + + if (!proxy) { + pswitch(1); + } + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + longjmp(abortprox,1); +} + +void +doproxy(argc, argv) + int argc; + char *argv[]; +{ + struct cmd *c; + sig_t oldintr; + + if (argc < 2 && !another(&argc, &argv, "command")) { + printf("usage: %s command\n", argv[0]); + code = -1; + return; + } + c = getcmd(argv[1]); + if (c == (struct cmd *) -1) { + printf("?Ambiguous command\n"); + (void) fflush(stdout); + code = -1; + return; + } + if (c == 0) { + printf("?Invalid command\n"); + (void) fflush(stdout); + code = -1; + return; + } + if (!c->c_proxy) { + printf("?Invalid proxy command\n"); + (void) fflush(stdout); + code = -1; + return; + } + if (setjmp(abortprox)) { + code = -1; + return; + } + oldintr = signal(SIGINT, proxabort); + pswitch(1); + if (c->c_conn && !connected) { + printf("Not connected\n"); + (void) fflush(stdout); + pswitch(0); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + (*c->c_handler)(argc-1, argv+1); + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + (void) signal(SIGINT, oldintr); +} + +void +setcase(argc, argv) + int argc; + char *argv[]; +{ + + mcase = !mcase; + printf("Case mapping %s.\n", onoff(mcase)); + code = mcase; +} + +void +setcr(argc, argv) + int argc; + char *argv[]; +{ + + crflag = !crflag; + printf("Carriage Return stripping %s.\n", onoff(crflag)); + code = crflag; +} + +void +setntrans(argc,argv) + int argc; + char *argv[]; +{ + if (argc == 1) { + ntflag = 0; + printf("Ntrans off.\n"); + code = ntflag; + return; + } + ntflag++; + code = ntflag; + (void) strncpy(ntin, argv[1], 16); + ntin[16] = '\0'; + if (argc == 2) { + ntout[0] = '\0'; + return; + } + (void) strncpy(ntout, argv[2], 16); + ntout[16] = '\0'; +} + +char * +dotrans(name) + char *name; +{ + static char new[MAXPATHLEN]; + char *cp1, *cp2 = new; + int i, ostop, found; + + for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) + continue; + for (cp1 = name; *cp1; cp1++) { + found = 0; + for (i = 0; *(ntin + i) && i < 16; i++) { + if (*cp1 == *(ntin + i)) { + found++; + if (i < ostop) { + *cp2++ = *(ntout + i); + } + break; + } + } + if (!found) { + *cp2++ = *cp1; + } + } + *cp2 = '\0'; + return (new); +} + +void +setnmap(argc, argv) + int argc; + char *argv[]; +{ + char *cp; + + if (argc == 1) { + mapflag = 0; + printf("Nmap off.\n"); + code = mapflag; + return; + } + if (argc < 3 && !another(&argc, &argv, "mapout")) { + printf("Usage: %s [mapin mapout]\n",argv[0]); + code = -1; + return; + } + mapflag = 1; + code = 1; + cp = strchr(altarg, ' '); + if (proxy) { + while(*++cp == ' ') + continue; + altarg = cp; + cp = strchr(altarg, ' '); + } + *cp = '\0'; + (void) strncpy(mapin, altarg, MAXPATHLEN - 1); + while (*++cp == ' ') + continue; + (void) strncpy(mapout, cp, MAXPATHLEN - 1); +} + +char * +domap(name) + char *name; +{ + static char new[MAXPATHLEN]; + char *cp1 = name, *cp2 = mapin; + char *tp[9], *te[9]; + int i, toks[9], toknum = 0, match = 1; + + for (i=0; i < 9; ++i) { + toks[i] = 0; + } + while (match && *cp1 && *cp2) { + switch (*cp2) { + case '\\': + if (*++cp2 != *cp1) { + match = 0; + } + break; + case '$': + if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { + if (*cp1 != *(++cp2+1)) { + toks[toknum = *cp2 - '1']++; + tp[toknum] = cp1; + while (*++cp1 && *(cp2+1) + != *cp1); + te[toknum] = cp1; + } + cp2++; + break; + } + /* FALLTHROUGH */ + default: + if (*cp2 != *cp1) { + match = 0; + } + break; + } + if (match && *cp1) { + cp1++; + } + if (match && *cp2) { + cp2++; + } + } + if (!match && *cp1) /* last token mismatch */ + { + toks[toknum] = 0; + } + cp1 = new; + *cp1 = '\0'; + cp2 = mapout; + while (*cp2) { + match = 0; + switch (*cp2) { + case '\\': + if (*(cp2 + 1)) { + *cp1++ = *++cp2; + } + break; + case '[': +LOOP: + if (*++cp2 == '$' && isdigit(*(cp2+1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + match = 1; + } + else if (toks[toknum = *cp2 - '1']) { + char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp1++ = *cp3++; + } + match = 1; + } + } + else { + while (*cp2 && *cp2 != ',' && + *cp2 != ']') { + if (*cp2 == '\\') { + cp2++; + } + else if (*cp2 == '$' && + isdigit(*(cp2+1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + } + else if (toks[toknum = + *cp2 - '1']) { + char *cp3=tp[toknum]; + + while (cp3 != + te[toknum]) { + *cp1++ = *cp3++; + } + } + } + else if (*cp2) { + *cp1++ = *cp2++; + } + } + if (!*cp2) { + printf("nmap: unbalanced brackets\n"); + return (name); + } + match = 1; + cp2--; + } + if (match) { + while (*++cp2 && *cp2 != ']') { + if (*cp2 == '\\' && *(cp2 + 1)) { + cp2++; + } + } + if (!*cp2) { + printf("nmap: unbalanced brackets\n"); + return (name); + } + break; + } + switch (*++cp2) { + case ',': + goto LOOP; + case ']': + break; + default: + cp2--; + goto LOOP; + } + break; + case '$': + if (isdigit(*(cp2 + 1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + } + else if (toks[toknum = *cp2 - '1']) { + char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp1++ = *cp3++; + } + } + break; + } + /* intentional drop through */ + default: + *cp1++ = *cp2; + break; + } + cp2++; + } + *cp1 = '\0'; + if (!*new) { + return (name); + } + return (new); +} + +void +setsunique(argc, argv) + int argc; + char *argv[]; +{ + + sunique = !sunique; + printf("Store unique %s.\n", onoff(sunique)); + code = sunique; +} + +void +setrunique(argc, argv) + int argc; + char *argv[]; +{ + + runique = !runique; + printf("Receive unique %s.\n", onoff(runique)); + code = runique; +} + +/* change directory to perent directory */ +void +cdup(argc, argv) + int argc; + char *argv[]; +{ + + if (command("CDUP") == ERROR && code == 500) { + if (verbose) + printf("CDUP command not recognized, trying XCUP\n"); + (void) command("XCUP"); + } +} + +/* restart transfer at specific point */ +void +restart(argc, argv) + int argc; + char *argv[]; +{ + + if (argc != 2) + printf("restart: offset not specified\n"); + else { + restart_point = atol(argv[1]); + printf("restarting at %qd. %s\n", restart_point, + "execute get, put or append to initiate transfer"); + } +} + +/* show remote system type */ +void +syst(argc, argv) + int argc; + char *argv[]; +{ + + (void) command("SYST"); +} + +void +macdef(argc, argv) + int argc; + char *argv[]; +{ + char *tmp; + int c; + + if (macnum == 16) { + printf("Limit of 16 macros have already been defined\n"); + code = -1; + return; + } + if (argc < 2 && !another(&argc, &argv, "macro name")) { + printf("Usage: %s macro_name\n",argv[0]); + code = -1; + return; + } + if (interactive) { + printf("Enter macro line by line, terminating it with a null line\n"); + } + (void) strncpy(macros[macnum].mac_name, argv[1], 8); + if (macnum == 0) { + macros[macnum].mac_start = macbuf; + } + else { + macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; + } + tmp = macros[macnum].mac_start; + while (tmp != macbuf+4096) { + if ((c = getchar()) == EOF) { + printf("macdef:end of file encountered\n"); + code = -1; + return; + } + if ((*tmp = c) == '\n') { + if (tmp == macros[macnum].mac_start) { + macros[macnum++].mac_end = tmp; + code = 0; + return; + } + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + code = 0; + return; + } + *tmp = '\0'; + } + tmp++; + } + while (1) { + while ((c = getchar()) != '\n' && c != EOF) + /* LOOP */; + if (c == EOF || getchar() == '\n') { + printf("Macro not defined - 4k buffer exceeded\n"); + code = -1; + return; + } + } +} + +/* + * get size of file on remote machine + */ +void +sizecmd(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "filename")) { + printf("usage: %s filename\n", argv[0]); + code = -1; + return; + } + (void) command("SIZE %s", argv[1]); +} + +/* + * get last modification time of file on remote machine + */ +void +modtime(argc, argv) + int argc; + char *argv[]; +{ + int overbose; + + if (argc < 2 && !another(&argc, &argv, "filename")) { + printf("usage: %s filename\n", argv[0]); + code = -1; + return; + } + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("MDTM %s", argv[1]) == COMPLETE) { + int yy, mo, day, hour, min, sec; + sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, + &day, &hour, &min, &sec); + /* might want to print this in local time */ + printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], + mo, day, yy, hour, min, sec); + } else + printf("%s\n", reply_string); + verbose = overbose; +} + +/* + * show status on reomte machine + */ +void +rmtstatus(argc, argv) + int argc; + char *argv[]; +{ + + (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); +} + +/* + * get file if modtime is more recent than current file + */ +void +newer(argc, argv) + int argc; + char *argv[]; +{ + + if (getit(argc, argv, -1, "w")) + printf("Local file \"%s\" is newer than remote file \"%s\"\n", + argv[2], argv[1]); +} diff --git a/usr.bin/ftp/cmdtab.c b/usr.bin/ftp/cmdtab.c new file mode 100644 index 0000000..db3b755 --- /dev/null +++ b/usr.bin/ftp/cmdtab.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1985, 1989, 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[] = "@(#)cmdtab.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include "ftp_var.h" + +/* + * User FTP -- Command Tables. + */ + +char accounthelp[] = "send account command to remote server"; +char appendhelp[] = "append to a file"; +char asciihelp[] = "set ascii transfer type"; +char beephelp[] = "beep when command completed"; +char binaryhelp[] = "set binary transfer type"; +char casehelp[] = "toggle mget upper/lower case id mapping"; +char cdhelp[] = "change remote working directory"; +char cduphelp[] = "change remote working directory to parent directory"; +char chmodhelp[] = "change file permissions of remote file"; +char connecthelp[] = "connect to remote tftp"; +char crhelp[] = "toggle carriage return stripping on ascii gets"; +char deletehelp[] = "delete remote file"; +char debughelp[] = "toggle/set debugging mode"; +char dirhelp[] = "list contents of remote directory"; +char disconhelp[] = "terminate ftp session"; +char domachelp[] = "execute macro"; +char formhelp[] = "set file transfer format"; +char globhelp[] = "toggle metacharacter expansion of local file names"; +char hashhelp[] = "toggle printing `#' for each buffer transferred"; +char helphelp[] = "print local help information"; +char idlehelp[] = "get (set) idle timer on remote side"; +char lcdhelp[] = "change local working directory"; +char lshelp[] = "list contents of remote directory"; +char macdefhelp[] = "define a macro"; +char mdeletehelp[] = "delete multiple files"; +char mdirhelp[] = "list contents of multiple remote directories"; +char mgethelp[] = "get multiple files"; +char mkdirhelp[] = "make directory on the remote machine"; +char mlshelp[] = "list contents of multiple remote directories"; +char modtimehelp[] = "show last modification time of remote file"; +char modehelp[] = "set file transfer mode"; +char mputhelp[] = "send multiple files"; +char newerhelp[] = "get file if remote file is newer than local file "; +char nlisthelp[] = "nlist contents of remote directory"; +char nmaphelp[] = "set templates for default file name mapping"; +char ntranshelp[] = "set translation table for default file name mapping"; +char porthelp[] = "toggle use of PORT cmd for each data connection"; +char prompthelp[] = "force interactive prompting on multiple commands"; +char proxyhelp[] = "issue command on alternate connection"; +char pwdhelp[] = "print working directory on remote machine"; +char quithelp[] = "terminate ftp session and exit"; +char quotehelp[] = "send arbitrary ftp command"; +char receivehelp[] = "receive file"; +char regethelp[] = "get file restarting at end of local file"; +char remotehelp[] = "get help from remote server"; +char renamehelp[] = "rename file"; +char restarthelp[]= "restart file transfer at bytecount"; +char rmdirhelp[] = "remove directory on the remote machine"; +char rmtstatushelp[]="show status of remote machine"; +char runiquehelp[] = "toggle store unique for local files"; +char resethelp[] = "clear queued command replies"; +char sendhelp[] = "send one file"; +char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information"; +char shellhelp[] = "escape to the shell"; +char sizecmdhelp[] = "show size of remote file"; +char statushelp[] = "show current status"; +char structhelp[] = "set file transfer structure"; +char suniquehelp[] = "toggle store unique on remote machine"; +char systemhelp[] = "show remote system type"; +char tenexhelp[] = "set tenex file transfer type"; +char tracehelp[] = "toggle packet tracing"; +char typehelp[] = "set file transfer type"; +char umaskhelp[] = "get (set) umask on remote side"; +char userhelp[] = "send new user information"; +char verbosehelp[] = "toggle verbose mode"; + +struct cmd cmdtab[] = { + { "!", shellhelp, 0, 0, 0, shell }, + { "$", domachelp, 1, 0, 0, domacro }, + { "account", accounthelp, 0, 1, 1, account}, + { "append", appendhelp, 1, 1, 1, put }, + { "ascii", asciihelp, 0, 1, 1, setascii }, + { "bell", beephelp, 0, 0, 0, setbell }, + { "binary", binaryhelp, 0, 1, 1, setbinary }, + { "bye", quithelp, 0, 0, 0, quit }, + { "case", casehelp, 0, 0, 1, setcase }, + { "cd", cdhelp, 0, 1, 1, cd }, + { "cdup", cduphelp, 0, 1, 1, cdup }, + { "chmod", chmodhelp, 0, 1, 1, do_chmod }, + { "close", disconhelp, 0, 1, 1, disconnect }, + { "cr", crhelp, 0, 0, 0, setcr }, + { "delete", deletehelp, 0, 1, 1, delete }, + { "debug", debughelp, 0, 0, 0, setdebug }, + { "dir", dirhelp, 1, 1, 1, ls }, + { "disconnect", disconhelp, 0, 1, 1, disconnect }, + { "form", formhelp, 0, 1, 1, setform }, + { "get", receivehelp, 1, 1, 1, get }, + { "glob", globhelp, 0, 0, 0, setglob }, + { "hash", hashhelp, 0, 0, 0, sethash }, + { "help", helphelp, 0, 0, 1, help }, + { "idle", idlehelp, 0, 1, 1, idle }, + { "image", binaryhelp, 0, 1, 1, setbinary }, + { "lcd", lcdhelp, 0, 0, 0, lcd }, + { "ls", lshelp, 1, 1, 1, ls }, + { "macdef", macdefhelp, 0, 0, 0, macdef }, + { "mdelete", mdeletehelp, 1, 1, 1, mdelete }, + { "mdir", mdirhelp, 1, 1, 1, mls }, + { "mget", mgethelp, 1, 1, 1, mget }, + { "mkdir", mkdirhelp, 0, 1, 1, makedir }, + { "mls", mlshelp, 1, 1, 1, mls }, + { "mode", modehelp, 0, 1, 1, setftmode }, + { "modtime", modtimehelp, 0, 1, 1, modtime }, + { "mput", mputhelp, 1, 1, 1, mput }, + { "newer", newerhelp, 1, 1, 1, newer }, + { "nmap", nmaphelp, 0, 0, 1, setnmap }, + { "nlist", nlisthelp, 1, 1, 1, ls }, + { "ntrans", ntranshelp, 0, 0, 1, setntrans }, + { "open", connecthelp, 0, 0, 1, setpeer }, + { "prompt", prompthelp, 0, 0, 0, setprompt }, + { "proxy", proxyhelp, 0, 0, 1, doproxy }, + { "sendport", porthelp, 0, 0, 0, setport }, + { "put", sendhelp, 1, 1, 1, put }, + { "pwd", pwdhelp, 0, 1, 1, pwd }, + { "quit", quithelp, 0, 0, 0, quit }, + { "quote", quotehelp, 1, 1, 1, quote }, + { "recv", receivehelp, 1, 1, 1, get }, + { "reget", regethelp, 1, 1, 1, reget }, + { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus }, + { "rhelp", remotehelp, 0, 1, 1, rmthelp }, + { "rename", renamehelp, 0, 1, 1, renamefile }, + { "reset", resethelp, 0, 1, 1, reset }, + { "restart", restarthelp, 1, 1, 1, restart }, + { "rmdir", rmdirhelp, 0, 1, 1, removedir }, + { "runique", runiquehelp, 0, 0, 1, setrunique }, + { "send", sendhelp, 1, 1, 1, put }, + { "site", sitehelp, 0, 1, 1, site }, + { "size", sizecmdhelp, 1, 1, 1, sizecmd }, + { "status", statushelp, 0, 0, 1, status }, + { "struct", structhelp, 0, 1, 1, setstruct }, + { "system", systemhelp, 0, 1, 1, syst }, + { "sunique", suniquehelp, 0, 0, 1, setsunique }, + { "tenex", tenexhelp, 0, 1, 1, settenex }, + { "trace", tracehelp, 0, 0, 0, settrace }, + { "type", typehelp, 0, 1, 1, settype }, + { "user", userhelp, 0, 1, 1, user }, + { "umask", umaskhelp, 0, 1, 1, do_umask }, + { "verbose", verbosehelp, 0, 0, 0, setverbose }, + { "?", helphelp, 0, 0, 1, help }, + { 0 }, +}; + +int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1; diff --git a/usr.bin/ftp/domacro.c b/usr.bin/ftp/domacro.c new file mode 100644 index 0000000..9644487 --- /dev/null +++ b/usr.bin/ftp/domacro.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1985, 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[] = "@(#)domacro.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "ftp_var.h" + +void +domacro(argc, argv) + int argc; + char *argv[]; +{ + int i, j, count = 2, loopflg = 0; + char *cp1, *cp2, line2[200]; + struct cmd *c; + + if (argc < 2 && !another(&argc, &argv, "macro name")) { + printf("Usage: %s macro_name.\n", argv[0]); + code = -1; + return; + } + for (i = 0; i < macnum; ++i) { + if (!strncmp(argv[1], macros[i].mac_name, 9)) { + break; + } + } + if (i == macnum) { + printf("'%s' macro not found.\n", argv[1]); + code = -1; + return; + } + (void) strcpy(line2, line); +TOP: + cp1 = macros[i].mac_start; + while (cp1 != macros[i].mac_end) { + while (isspace(*cp1)) { + cp1++; + } + cp2 = line; + while (*cp1 != '\0') { + switch(*cp1) { + case '\\': + *cp2++ = *++cp1; + break; + case '$': + if (isdigit(*(cp1+1))) { + j = 0; + while (isdigit(*++cp1)) { + j = 10*j + *cp1 - '0'; + } + cp1--; + if (argc - 2 >= j) { + (void) strcpy(cp2, argv[j+1]); + cp2 += strlen(argv[j+1]); + } + break; + } + if (*(cp1+1) == 'i') { + loopflg = 1; + cp1++; + if (count < argc) { + (void) strcpy(cp2, argv[count]); + cp2 += strlen(argv[count]); + } + break; + } + /* intentional drop through */ + default: + *cp2++ = *cp1; + break; + } + if (*cp1 != '\0') { + cp1++; + } + } + *cp2 = '\0'; + makeargv(); + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + code = -1; + } + else if (c == 0) { + printf("?Invalid command\n"); + code = -1; + } + else if (c->c_conn && !connected) { + printf("Not connected.\n"); + code = -1; + } + else { + if (verbose) { + printf("%s\n",line); + } + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) { + (void) putchar('\007'); + } + (void) strcpy(line, line2); + makeargv(); + argc = margc; + argv = margv; + } + if (cp1 != macros[i].mac_end) { + cp1++; + } + } + if (loopflg && ++count < argc) { + goto TOP; + } +} diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h new file mode 100644 index 0000000..349aea3 --- /dev/null +++ b/usr.bin/ftp/extern.h @@ -0,0 +1,152 @@ +/*- + * 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. + * + * @(#)extern.h 8.2 (Berkeley) 4/3/94 + */ + +struct timeval; +struct fd_set; + +void abort_remote __P((FILE *)); +void abortpt __P(()); +void abortrecv __P(()); +void abortsend __P(()); +void account __P((int, char **)); +int another __P((int *, char ***, char *)); +void blkfree __P((char **)); +void cd __P((int, char **)); +void cdup __P((int, char **)); +void changetype __P((int, int)); +void cmdabort __P(()); +void cmdscanner __P((int)); +int command __P(()); +int confirm __P((char *, char *)); +FILE *dataconn __P((char *)); +void delete __P((int, char **)); +void disconnect __P((int, char **)); +void do_chmod __P((int, char **)); +void do_umask __P((int, char **)); +void domacro __P((int, char **)); +char *domap __P((char *)); +void doproxy __P((int, char **)); +char *dotrans __P((char *)); +int empty __P((struct fd_set *, int)); +void fatal __P((char *)); +void get __P((int, char **)); +struct cmd *getcmd __P((char *)); +int getit __P((int, char **, int, char *)); +int getreply __P((int)); +int globulize __P((char **)); +char *gunique __P((char *)); +void help __P((int, char **)); +char *hookup __P((char *, int)); +void idle __P((int, char **)); +int initconn __P((void)); +void intr __P(()); +void lcd __P((int, char **)); +int login __P((char *)); +void lostpeer __P(()); +void ls __P((int, char **)); +void mabort __P((int)); +void macdef __P((int, char **)); +void makeargv __P((void)); +void makedir __P((int, char **)); +void mdelete __P((int, char **)); +void mget __P((int, char **)); +void mls __P((int, char **)); +void modtime __P((int, char **)); +void mput __P((int, char **)); +char *onoff __P((int)); +void newer __P((int, char **)); +void proxabort __P(()); +void proxtrans __P((char *, char *, char *)); +void psabort __P(()); +void pswitch __P((int)); +void ptransfer __P((char *, long, struct timeval *, struct timeval *)); +void put __P((int, char **)); +void pwd __P((int, char **)); +void quit __P((int, char **)); +void quote __P((int, char **)); +void quote1 __P((char *, int, char **)); +void recvrequest __P((char *, char *, char *, char *, int)); +void reget __P((int, char **)); +char *remglob __P((char **, int)); +void removedir __P((int, char **)); +void renamefile __P((int, char **)); +void reset __P((int, char **)); +void restart __P((int, char **)); +void rmthelp __P((int, char **)); +void rmtstatus __P((int, char **)); +int ruserpass __P((char *, char **, char **, char **)); +void sendrequest __P((char *, char *, char *, int)); +void setascii __P((int, char **)); +void setbell __P((int, char **)); +void setbinary __P((int, char **)); +void setcase __P((int, char **)); +void setcr __P((int, char **)); +void setdebug __P((int, char **)); +void setform __P((int, char **)); +void setftmode __P((int, char **)); +void setglob __P((int, char **)); +void sethash __P((int, char **)); +void setnmap __P((int, char **)); +void setntrans __P((int, char **)); +void setpeer __P((int, char **)); +void setport __P((int, char **)); +void setprompt __P((int, char **)); +void setrunique __P((int, char **)); +void setstruct __P((int, char **)); +void setsunique __P((int, char **)); +void settenex __P((int, char **)); +void settrace __P((int, char **)); +void settype __P((int, char **)); +void setverbose __P((int, char **)); +void shell __P((int, char **)); +void site __P((int, char **)); +void sizecmd __P((int, char **)); +char *slurpstring __P((void)); +void status __P((int, char **)); +void syst __P((int, char **)); +void tvsub __P((struct timeval *, struct timeval *, struct timeval *)); +void user __P((int, char **)); + +extern jmp_buf abortprox; +extern int abrtflag; +extern struct cmd cmdtab[]; +extern FILE *cout; +extern int data; +extern char *home; +extern jmp_buf jabort; +extern int proxy; +extern char reply_string[]; +extern off_t restart_point; +extern int NCMDS; diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1 new file mode 100644 index 0000000..417da08 --- /dev/null +++ b/usr.bin/ftp/ftp.1 @@ -0,0 +1,1136 @@ +.\" Copyright (c) 1985, 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ftp.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt FTP 1 +.Os BSD 4.2 +.Sh NAME +.Nm ftp +.Nd +.Tn ARPANET +file transfer program +.Sh SYNOPSIS +.Nm ftp +.Op Fl v +.Op Fl d +.Op Fl i +.Op Fl n +.Op Fl g +.Op Ar host +.Sh DESCRIPTION +.Nm Ftp +is the user interface to the +.Tn ARPANET +standard File Transfer Protocol. +The program allows a user to transfer files to and from a +remote network site. +.Pp +Options may be specified at the command line, or to the +command interpreter. +.Bl -tag -width flag +.It Fl v +Verbose option forces +.Nm ftp +to show all responses from the remote server, as well +as report on data transfer statistics. +.It Fl n +Restrains +.Nm ftp +from attempting \*(Lqauto-login\*(Rq upon initial connection. +If auto-login is enabled, +.Nm ftp +will check the +.Pa .netrc +(see below) file in the user's home directory for an entry describing +an account on the remote machine. +If no entry exists, +.Nm ftp +will prompt for the remote machine login name (default is the user +identity on the local machine), and, if necessary, prompt for a password +and an account with which to login. +.It Fl i +Turns off interactive prompting during +multiple file transfers. +.It Fl d +Enables debugging. +.It Fl g +Disables file name globbing. +.El +.Pp +The client host with which +.Nm ftp +is to communicate may be specified on the command line. +If this is done, +.Nm ftp +will immediately attempt to establish a connection to an +.Tn FTP +server on that host; otherwise, +.Nm ftp +will enter its command interpreter and await instructions +from the user. +When +.Nm ftp +is awaiting commands from the user the prompt +.Ql ftp> +is provided to the user. +The following commands are recognized +by +.Nm ftp : +.Bl -tag -width Fl +.It Ic \&! Op Ar command Op Ar args +Invoke an interactive shell on the local machine. +If there are arguments, the first is taken to be a command to execute +directly, with the rest of the arguments as its arguments. +.It Ic \&$ Ar macro-name Op Ar args +Execute the macro +.Ar macro-name +that was defined with the +.Ic macdef +command. +Arguments are passed to the macro unglobbed. +.It Ic account Op Ar passwd +Supply a supplemental password required by a remote system for access +to resources once a login has been successfully completed. +If no argument is included, the user will be prompted for an account +password in a non-echoing input mode. +.It Ic append Ar local-file Op Ar remote-file +Append a local file to a file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used in naming the +remote file after being altered by any +.Ic ntrans +or +.Ic nmap +setting. +File transfer uses the current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic ascii +Set the file transfer +.Ic type +to network +.Tn ASCII . +This is the default type. +.It Ic bell +Arrange that a bell be sounded after each file transfer +command is completed. +.It Ic binary +Set the file transfer +.Ic type +to support binary image transfer. +.It Ic bye +Terminate the +.Tn FTP +session with the remote server +and exit +.Nm ftp . +An end of file will also terminate the session and exit. +.It Ic case +Toggle remote computer file name case mapping during +.Ic mget +commands. +When +.Ic case +is on (default is off), remote computer file names with all letters in +upper case are written in the local directory with the letters mapped +to lower case. +.It Ic \&cd Ar remote-directory +Change the working directory on the remote machine +to +.Ar remote-directory . +.It Ic cdup +Change the remote machine working directory to the parent of the +current remote machine working directory. +.It Ic chmod Ar mode file-name +Change the permission modes of the file +.Ar file-name +on the remote +sytem to +.Ar mode . +.It Ic close +Terminate the +.Tn FTP +session with the remote server, and +return to the command interpreter. +Any defined macros are erased. +.It Ic \&cr +Toggle carriage return stripping during +ascii type file retrieval. +Records are denoted by a carriage return/linefeed sequence +during ascii type file transfer. +When +.Ic \&cr +is on (the default), carriage returns are stripped from this +sequence to conform with the +.Ux +single linefeed record +delimiter. +Records on +.Pf non\- Ns Ux +remote systems may contain single linefeeds; +when an ascii type transfer is made, these linefeeds may be +distinguished from a record delimiter only when +.Ic \&cr +is off. +.It Ic delete Ar remote-file +Delete the file +.Ar remote-file +on the remote machine. +.It Ic debug Op Ar debug-value +Toggle debugging mode. +If an optional +.Ar debug-value +is specified it is used to set the debugging level. +When debugging is on, +.Nm ftp +prints each command sent to the remote machine, preceded +by the string +.Ql \-\-> +.It Xo +.Ic dir +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a listing of the directory contents in the +directory, +.Ar remote-directory , +and, optionally, placing the output in +.Ar local-file . +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic dir +output. +If no directory is specified, the current working +directory on the remote machine is used. +If no local +file is specified, or +.Ar local-file +is +.Fl , +output comes to the terminal. +.It Ic disconnect +A synonym for +.Ar close . +.It Ic form Ar format +Set the file transfer +.Ic form +to +.Ar format . +The default format is \*(Lqfile\*(Rq. +.It Ic get Ar remote-file Op Ar local-file +Retrieve the +.Ar remote-file +and store it on the local machine. +If the local +file name is not specified, it is given the same +name it has on the remote machine, subject to +alteration by the current +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +The current settings for +.Ic type , +.Ic form , +.Ic mode , +and +.Ic structure +are used while transferring the file. +.It Ic glob +Toggle filename expansion for +.Ic mdelete , +.Ic mget +and +.Ic mput . +If globbing is turned off with +.Ic glob , +the file name arguments +are taken literally and not expanded. +Globbing for +.Ic mput +is done as in +.Xr csh 1 . +For +.Ic mdelete +and +.Ic mget , +each remote file name is expanded +separately on the remote machine and the lists are not merged. +Expansion of a directory name is likely to be +different from expansion of the name of an ordinary file: +the exact result depends on the foreign operating system and ftp server, +and can be previewed by doing +.Ql mls remote-files \- +Note: +.Ic mget +and +.Ic mput +are not meant to transfer +entire directory subtrees of files. +That can be done by +transferring a +.Xr tar 1 +archive of the subtree (in binary mode). +.It Ic hash +Toggle hash-sign (``#'') printing for each data block +transferred. +The size of a data block is 1024 bytes. +.It Ic help Op Ar command +Print an informative message about the meaning of +.Ar command . +If no argument is given, +.Nm ftp +prints a list of the known commands. +.It Ic idle Op Ar seconds +Set the inactivity timer on the remote server to +.Ar seconds +seconds. +If +.Ar seconds +is omitted, the current inactivity timer is printed. +.It Ic lcd Op Ar directory +Change the working directory on the local machine. +If +no +.Ar directory +is specified, the user's home directory is used. +.It Xo +.Ic \&ls +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a listing of the contents of a +directory on the remote machine. +The listing includes any system-dependent information that the server +chooses to include; for example, most +.Ux +systems will produce +output from the command +.Ql ls \-l . +(See also +.Ic nlist . ) +If +.Ar remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic \&ls +output. +If no local file is specified, or if +.Ar local-file +is +.Sq Fl , +the output is sent to the terminal. +.It Ic macdefNs Ar macro-name +Define a macro. +Subsequent lines are stored as the macro +.Ar macro-name ; +a null line (consecutive newline characters +in a file or +carriage returns from the terminal) terminates macro input mode. +There is a limit of 16 macros and 4096 total characters in all +defined macros. +Macros remain defined until a +.Ic close +command is executed. +The macro processor interprets `$' and `\e' as special characters. +A `$' followed by a number (or numbers) is replaced by the +corresponding argument on the macro invocation command line. +A `$' followed by an `i' signals that macro processor that the +executing macro is to be looped. +On the first pass `$i' is +replaced by the first argument on the macro invocation command line, +on the second pass it is replaced by the second argument, and so on. +A `\e' followed by any character is replaced by that character. +Use the `\e' to prevent special treatment of the `$'. +.It Ic mdelete Op Ar remote-files +Delete the +.Ar remote-files +on the remote machine. +.It Ic mdir Ar remote-files local-file +Like +.Ic dir , +except multiple remote files may be specified. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mdir +output. +.It Ic mget Ar remote-files +Expand the +.Ar remote-files +on the remote machine +and do a +.Ic get +for each file name thus produced. +See +.Ic glob +for details on the filename expansion. +Resulting file names will then be processed according to +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +Files are transferred into the local working directory, +which can be changed with +.Ql lcd directory ; +new local directories can be created with +.Ql "\&! mkdir directory" . +.It Ic mkdir Ar directory-name +Make a directory on the remote machine. +.It Ic mls Ar remote-files local-file +Like +.Ic nlist , +except multiple remote files may be specified, +and the +.Ar local-file +must be specified. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mls +output. +.It Ic mode Op Ar mode-name +Set the file transfer +.Ic mode +to +.Ar mode-name . +The default mode is \*(Lqstream\*(Rq mode. +.It Ic modtime Ar file-name +Show the last modification time of the file on the remote machine. +.It Ic mput Ar local-files +Expand wild cards in the list of local files given as arguments +and do a +.Ic put +for each file in the resulting list. +See +.Ic glob +for details of filename expansion. +Resulting file names will then be processed according to +.Ic ntrans +and +.Ic nmap +settings. +.It Ic newer Ar file-name +Get the file only if the modification time of the remote file is more +recent that the file on the current system. +If the file does not +exist on the current system, the remote file is considered +.Ic newer . +Otherwise, this command is identical to +.Ar get . +.It Xo +.Ic nlist +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a list of the files in a +directory on the remote machine. +If +.Ar remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic nlist +output. +If no local file is specified, or if +.Ar local-file +is +.Fl , +the output is sent to the terminal. +.It Ic nmap Op Ar inpattern outpattern +Set or unset the filename mapping mechanism. +If no arguments are specified, the filename mapping mechanism is unset. +If arguments are specified, remote filenames are mapped during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, local filenames are mapped during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +The mapping follows the pattern set by +.Ar inpattern +and +.Ar outpattern . +.Op Ar Inpattern +is a template for incoming filenames (which may have already been +processed according to the +.Ic ntrans +and +.Ic case +settings). +Variable templating is accomplished by including the +sequences `$1', `$2', ..., `$9' in +.Ar inpattern . +Use `\\' to prevent this special treatment of the `$' character. +All other characters are treated literally, and are used to determine the +.Ic nmap +.Op Ar inpattern +variable values. +For example, given +.Ar inpattern +$1.$2 and the remote file name "mydata.data", $1 would have the value +"mydata", and $2 would have the value "data". +The +.Ar outpattern +determines the resulting mapped filename. +The sequences `$1', `$2', ...., `$9' are replaced by any value resulting +from the +.Ar inpattern +template. +The sequence `$0' is replace by the original filename. +Additionally, the sequence +.Ql Op Ar seq1 , Ar seq2 +is replaced by +.Op Ar seq1 +if +.Ar seq1 +is not a null string; otherwise it is replaced by +.Ar seq2 . +For example, the command +.Pp +.Bd -literal -offset indent -compact +nmap $1.$2.$3 [$1,$2].[$2,file] +.Ed +.Pp +would yield +the output filename "myfile.data" for input filenames "myfile.data" and +"myfile.data.old", "myfile.file" for the input filename "myfile", and +"myfile.myfile" for the input filename ".myfile". +Spaces may be included in +.Ar outpattern , +as in the example: `nmap $1 sed "s/ *$//" > $1' . +Use the `\e' character to prevent special treatment +of the `$','[','[', and `,' characters. +.It Ic ntrans Op Ar inchars Op Ar outchars +Set or unset the filename character translation mechanism. +If no arguments are specified, the filename character +translation mechanism is unset. +If arguments are specified, characters in +remote filenames are translated during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, characters in +local filenames are translated during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +Characters in a filename matching a character in +.Ar inchars +are replaced with the corresponding character in +.Ar outchars . +If the character's position in +.Ar inchars +is longer than the length of +.Ar outchars , +the character is deleted from the file name. +.It Ic open Ar host Op Ar port +Establish a connection to the specified +.Ar host +.Tn FTP +server. +An optional port number may be supplied, +in which case, +.Nm ftp +will attempt to contact an +.Tn FTP +server at that port. +If the +.Ic auto-login +option is on (default), +.Nm ftp +will also attempt to automatically log the user in to +the +.Tn FTP +server (see below). +.It Ic prompt +Toggle interactive prompting. +Interactive prompting +occurs during multiple file transfers to allow the +user to selectively retrieve or store files. +If prompting is turned off (default is on), any +.Ic mget +or +.Ic mput +will transfer all files, and any +.Ic mdelete +will delete all files. +.It Ic proxy Ar ftp-command +Execute an ftp command on a secondary control connection. +This command allows simultaneous connection to two remote ftp +servers for transferring files between the two servers. +The first +.Ic proxy +command should be an +.Ic open , +to establish the secondary control connection. +Enter the command "proxy ?" to see other ftp commands executable on the +secondary connection. +The following commands behave differently when prefaced by +.Ic proxy : +.Ic open +will not define new macros during the auto-login process, +.Ic close +will not erase existing macro definitions, +.Ic get +and +.Ic mget +transfer files from the host on the primary control connection +to the host on the secondary control connection, and +.Ic put , +.Ic mput , +and +.Ic append +transfer files from the host on the secondary control connection +to the host on the primary control connection. +Third party file transfers depend upon support of the ftp protocol +.Dv PASV +command by the server on the secondary control connection. +.It Ic put Ar local-file Op Ar remote-file +Store a local file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used +after processing according to any +.Ic ntrans +or +.Ic nmap +settings +in naming the remote file. +File transfer uses the +current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic pwd +Print the name of the current working directory on the remote +machine. +.It Ic quit +A synonym for +.Ic bye . +.It Ic quote Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server. +.It Ic recv Ar remote-file Op Ar local-file +A synonym for get. +.It Ic reget Ar remote-file Op Ar local-file +Reget acts like get, except that if +.Ar local-file +exists and is +smaller than +.Ar remote-file , +.Ar local-file +is presumed to be +a partially transferred copy of +.Ar remote-file +and the transfer +is continued from the apparent point of failure. +This command +is useful when transferring very large files over networks that +are prone to dropping connections. +.It Ic remotehelp Op Ar command-name +Request help from the remote +.Tn FTP +server. +If a +.Ar command-name +is specified it is supplied to the server as well. +.It Ic remotestatus Op Ar file-name +With no arguments, show status of remote machine. +If +.Ar file-name +is specified, show status of +.Ar file-name +on remote machine. +.It Xo +.Ic rename +.Op Ar from +.Op Ar to +.Xc +Rename the file +.Ar from +on the remote machine, to the file +.Ar to . +.It Ic reset +Clear reply queue. +This command re-synchronizes command/reply sequencing with the remote +ftp server. +Resynchronization may be necessary following a violation of the ftp protocol +by the remote server. +.It Ic restart Ar marker +Restart the immediately following +.Ic get +or +.Ic put +at the +indicated +.Ar marker . +On +.Ux +systems, marker is usually a byte +offset into the file. +.It Ic rmdir Ar directory-name +Delete a directory on the remote machine. +.It Ic runique +Toggle storing of files on the local system with unique filenames. +If a file already exists with a name equal to the target +local filename for a +.Ic get +or +.Ic mget +command, a ".1" is appended to the name. +If the resulting name matches another existing file, +a ".2" is appended to the original name. +If this process continues up to ".99", an error +message is printed, and the transfer does not take place. +The generated unique filename will be reported. +Note that +.Ic runique +will not affect local files generated from a shell command +(see below). +The default value is off. +.It Ic send Ar local-file Op Ar remote-file +A synonym for put. +.It Ic sendport +Toggle the use of +.Dv PORT +commands. +By default, +.Nm ftp +will attempt to use a +.Dv PORT +command when establishing +a connection for each data transfer. +The use of +.Dv PORT +commands can prevent delays +when performing multiple file transfers. +If the +.Dv PORT +command fails, +.Nm ftp +will use the default data port. +When the use of +.Dv PORT +commands is disabled, no attempt will be made to use +.Dv PORT +commands for each data transfer. +This is useful +for certain +.Tn FTP +implementations which do ignore +.Dv PORT +commands but, incorrectly, indicate they've been accepted. +.It Ic site Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server as a +.Dv SITE +command. +.It Ic size Ar file-name +Return size of +.Ar file-name +on remote machine. +.It Ic status +Show the current status of +.Nm ftp . +.It Ic struct Op Ar struct-name +Set the file transfer +.Ar structure +to +.Ar struct-name . +By default \*(Lqstream\*(Rq structure is used. +.It Ic sunique +Toggle storing of files on remote machine under unique file names. +Remote ftp server must support ftp protocol +.Dv STOU +command for +successful completion. +The remote server will report unique name. +Default value is off. +.It Ic system +Show the type of operating system running on the remote machine. +.It Ic tenex +Set the file transfer type to that needed to +talk to +.Tn TENEX +machines. +.It Ic trace +Toggle packet tracing. +.It Ic type Op Ar type-name +Set the file transfer +.Ic type +to +.Ar type-name . +If no type is specified, the current type +is printed. +The default type is network +.Tn ASCII . +.It Ic umask Op Ar newmask +Set the default umask on the remote server to +.Ar newmask . +If +.Ar newmask +is omitted, the current umask is printed. +.It Xo +.Ic user Ar user-name +.Op Ar password +.Op Ar account +.Xc +Identify yourself to the remote +.Tn FTP +server. +If the +.Ar password +is not specified and the server requires it, +.Nm ftp +will prompt the user for it (after disabling local echo). +If an +.Ar account +field is not specified, and the +.Tn FTP +server +requires it, the user will be prompted for it. +If an +.Ar account +field is specified, an account command will +be relayed to the remote server after the login sequence +is completed if the remote server did not require it +for logging in. +Unless +.Nm ftp +is invoked with \*(Lqauto-login\*(Rq disabled, this +process is done automatically on initial connection to +the +.Tn FTP +server. +.It Ic verbose +Toggle verbose mode. +In verbose mode, all responses from +the +.Tn FTP +server are displayed to the user. +In addition, +if verbose is on, when a file transfer completes, statistics +regarding the efficiency of the transfer are reported. +By default, +verbose is on. +.It Ic ? Op Ar command +A synonym for help. +.El +.Pp +Command arguments which have embedded spaces may be quoted with +quote `"' marks. +.Sh ABORTING A FILE TRANSFER +To abort a file transfer, use the terminal interrupt key +(usually Ctrl-C). +Sending transfers will be immediately halted. +Receiving transfers will be halted by sending a ftp protocol +.Dv ABOR +command to the remote server, and discarding any further data received. +The speed at which this is accomplished depends upon the remote +server's support for +.Dv ABOR +processing. +If the remote server does not support the +.Dv ABOR +command, an +.Ql ftp> +prompt will not appear until the remote server has completed +sending the requested file. +.Pp +The terminal interrupt key sequence will be ignored when +.Nm ftp +has completed any local processing and is awaiting a reply +from the remote server. +A long delay in this mode may result from the ABOR processing described +above, or from unexpected behavior by the remote server, including +violations of the ftp protocol. +If the delay results from unexpected remote server behavior, the local +.Nm ftp +program must be killed by hand. +.Sh FILE NAMING CONVENTIONS +Files specified as arguments to +.Nm ftp +commands are processed according to the following rules. +.Bl -enum +.It +If the file name +.Sq Fl +is specified, the +.Ar stdin +(for reading) or +.Ar stdout +(for writing) is used. +.It +If the first character of the file name is +.Sq \&| , +the +remainder of the argument is interpreted as a shell command. +.Nm Ftp +then forks a shell, using +.Xr popen 3 +with the argument supplied, and reads (writes) from the stdout +(stdin). +If the shell command includes spaces, the argument +must be quoted; e.g. +\*(Lq" ls -lt"\*(Rq. +A particularly +useful example of this mechanism is: \*(Lqdir more\*(Rq. +.It +Failing the above checks, if ``globbing'' is enabled, +local file names are expanded +according to the rules used in the +.Xr csh 1 ; +c.f. the +.Ic glob +command. +If the +.Nm ftp +command expects a single local file (.e.g. +.Ic put ) , +only the first filename generated by the "globbing" operation is used. +.It +For +.Ic mget +commands and +.Ic get +commands with unspecified local file names, the local filename is +the remote filename, which may be altered by a +.Ic case , +.Ic ntrans , +or +.Ic nmap +setting. +The resulting filename may then be altered if +.Ic runique +is on. +.It +For +.Ic mput +commands and +.Ic put +commands with unspecified remote file names, the remote filename is +the local filename, which may be altered by a +.Ic ntrans +or +.Ic nmap +setting. +The resulting filename may then be altered by the remote server if +.Ic sunique +is on. +.El +.Sh FILE TRANSFER PARAMETERS +The FTP specification specifies many parameters which may +affect a file transfer. +The +.Ic type +may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary), +\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for +.Tn PDP Ns -10's +and +.Tn PDP Ns -20's +mostly). +.Nm Ftp +supports the ascii and image types of file transfer, +plus local byte size 8 for +.Ic tenex +mode transfers. +.Pp +.Nm Ftp +supports only the default values for the remaining +file transfer parameters: +.Ic mode , +.Ic form , +and +.Ic struct . +.Sh THE .netrc FILE +The +.Pa .netrc +file contains login and initialization information +used by the auto-login process. +It resides in the user's home directory. +The following tokens are recognized; they may be separated by spaces, +tabs, or new-lines: +.Bl -tag -width password +.It Ic machine Ar name +Identify a remote machine +.Ar name . +The auto-login process searches the +.Pa .netrc +file for a +.Ic machine +token that matches the remote machine specified on the +.Nm ftp +command line or as an +.Ic open +command argument. +Once a match is made, the subsequent +.Pa .netrc +tokens are processed, +stopping when the end of file is reached or another +.Ic machine +or a +.Ic default +token is encountered. +.It Ic default +This is the same as +.Ic machine +.Ar name +except that +.Ic default +matches any name. +There can be only one +.Ic default +token, and it must be after all +.Ic machine +tokens. +This is normally used as: +.Pp +.Dl default login anonymous password user@site +.Pp +thereby giving the user +.Ar automatic +anonymous ftp login to +machines not specified in +.Pa .netrc . +This can be overridden +by using the +.Fl n +flag to disable auto-login. +.It Ic login Ar name +Identify a user on the remote machine. +If this token is present, the auto-login process will initiate +a login using the specified +.Ar name . +.It Ic password Ar string +Supply a password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires a password as part +of the login process. +Note that if this token is present in the +.Pa .netrc +file for any user other +than +.Ar anonymous , +.Nm ftp +will abort the auto-login process if the +.Pa .netrc +is readable by +anyone besides the user. +.It Ic account Ar string +Supply an additional account password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires an additional +account password, or the auto-login process will initiate an +.Dv ACCT +command if it does not. +.It Ic macdef Ar name +Define a macro. +This token functions like the +.Nm ftp +.Ic macdef +command functions. +A macro is defined with the specified name; its contents begin with the +next +.Pa .netrc +line and continue until a null line (consecutive new-line +characters) is encountered. +If a macro named +.Ic init +is defined, it is automatically executed as the last step in the +auto-login process. +.El +.Sh ENVIRONMENT +.Nm Ftp +utilizes the following environment variables. +.Bl -tag -width Fl +.It Ev HOME +For default location of a +.Pa .netrc +file, if one exists. +.It Ev SHELL +For default shell. +.El +.Sh SEE ALSO +.Xr ftpd 8 +.Sh HISTORY +The +.Nm ftp +command appeared in +.Bx 4.2 . +.Sh BUGS +Correct execution of many commands depends upon proper behavior +by the remote server. +.Pp +An error in the treatment of carriage returns +in the +.Bx 4.2 +ascii-mode transfer code +has been corrected. +This correction may result in incorrect transfers of binary files +to and from +.Bx 4.2 +servers using the ascii type. +Avoid this problem by using the binary image type. diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c new file mode 100644 index 0000000..19e8f8e --- /dev/null +++ b/usr.bin/ftp/ftp.c @@ -0,0 +1,1470 @@ +/* + * Copyright (c) 1985, 1989, 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[] = "@(#)ftp.c 8.4 (Berkeley) 4/6/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +extern int h_errno; + +struct sockaddr_in hisctladdr; +struct sockaddr_in data_addr; +int data = -1; +int abrtflag = 0; +jmp_buf ptabort; +int ptabflg; +int ptflag = 0; +struct sockaddr_in myctladdr; +off_t restart_point = 0; + + +FILE *cin, *cout; + +char * +hookup(host, port) + char *host; + int port; +{ + struct hostent *hp = 0; + int s, len, tos; + static char hostnamebuf[80]; + + memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); + hisctladdr.sin_addr.s_addr = inet_addr(host); + if (hisctladdr.sin_addr.s_addr != -1) { + hisctladdr.sin_family = AF_INET; + (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); + } else { + hp = gethostbyname(host); + if (hp == NULL) { + warnx("%s: %s", host, hstrerror(h_errno)); + code = -1; + return ((char *) 0); + } + hisctladdr.sin_family = hp->h_addrtype; + memmove((caddr_t)&hisctladdr.sin_addr, + hp->h_addr_list[0], hp->h_length); + (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); + } + hostname = hostnamebuf; + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); + if (s < 0) { + warn("socket"); + code = -1; + return (0); + } + hisctladdr.sin_port = port; + while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { + if (hp && hp->h_addr_list[1]) { + int oerrno = errno; + char *ia; + + ia = inet_ntoa(hisctladdr.sin_addr); + errno = oerrno; + warn("connect to address %s", ia); + hp->h_addr_list++; + memmove((caddr_t)&hisctladdr.sin_addr, + hp->h_addr_list[0], hp->h_length); + fprintf(stdout, "Trying %s...\n", + inet_ntoa(hisctladdr.sin_addr)); + (void) close(s); + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); + if (s < 0) { + warn("socket"); + code = -1; + return (0); + } + continue; + } + warn("connect"); + code = -1; + goto bad; + } + len = sizeof (myctladdr); + if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { + warn("getsockname"); + code = -1; + goto bad; + } +#ifdef IP_TOS + tos = IPTOS_LOWDELAY; + if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif + cin = fdopen(s, "r"); + cout = fdopen(s, "w"); + if (cin == NULL || cout == NULL) { + warnx("fdopen failed."); + if (cin) + (void) fclose(cin); + if (cout) + (void) fclose(cout); + code = -1; + goto bad; + } + if (verbose) + printf("Connected to %s.\n", hostname); + if (getreply(0) > 2) { /* read startup message from server */ + if (cin) + (void) fclose(cin); + if (cout) + (void) fclose(cout); + code = -1; + goto bad; + } +#ifdef SO_OOBINLINE + { + int on = 1; + + if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) + < 0 && debug) { + warn("setsockopt"); + } + } +#endif /* SO_OOBINLINE */ + + return (hostname); +bad: + (void) close(s); + return ((char *)0); +} + +int +login(host) + char *host; +{ + char tmp[80]; + char *user, *pass, *acct; + int n, aflag = 0; + + user = pass = acct = 0; + if (ruserpass(host, &user, &pass, &acct) < 0) { + code = -1; + return (0); + } + while (user == NULL) { + char *myname = getlogin(); + + if (myname == NULL) { + struct passwd *pp = getpwuid(getuid()); + + if (pp != NULL) + myname = pp->pw_name; + } + if (myname) + printf("Name (%s:%s): ", host, myname); + else + printf("Name (%s): ", host); + (void) fgets(tmp, sizeof(tmp) - 1, stdin); + tmp[strlen(tmp) - 1] = '\0'; + if (*tmp == '\0') + user = myname; + else + user = tmp; + } + n = command("USER %s", user); + if (n == CONTINUE) { + if (pass == NULL) + pass = getpass("Password:"); + n = command("PASS %s", pass); + } + if (n == CONTINUE) { + aflag++; + acct = getpass("Account:"); + n = command("ACCT %s", acct); + } + if (n != COMPLETE) { + warnx("Login failed."); + return (0); + } + if (!aflag && acct != NULL) + (void) command("ACCT %s", acct); + if (proxy) + return (1); + for (n = 0; n < macnum; ++n) { + if (!strcmp("init", macros[n].mac_name)) { + (void) strcpy(line, "$init"); + makeargv(); + domacro(margc, margv); + break; + } + } + return (1); +} + +void +cmdabort() +{ + + printf("\n"); + (void) fflush(stdout); + abrtflag++; + if (ptflag) + longjmp(ptabort,1); +} + +/*VARARGS*/ +int +command(va_alist) +va_dcl +{ + va_list ap; + char *fmt; + int r; + sig_t oldintr; + + abrtflag = 0; + if (debug) { + printf("---> "); + va_start(ap); + fmt = va_arg(ap, char *); + if (strncmp("PASS ", fmt, 5) == 0) + printf("PASS XXXX"); + else + vfprintf(stdout, fmt, ap); + va_end(ap); + printf("\n"); + (void) fflush(stdout); + } + if (cout == NULL) { + warn("No control connection for command"); + code = -1; + return (0); + } + oldintr = signal(SIGINT, cmdabort); + va_start(ap); + fmt = va_arg(ap, char *); + vfprintf(cout, fmt, ap); + va_end(ap); + fprintf(cout, "\r\n"); + (void) fflush(cout); + cpend = 1; + r = getreply(!strcmp(fmt, "QUIT")); + if (abrtflag && oldintr != SIG_IGN) + (*oldintr)(SIGINT); + (void) signal(SIGINT, oldintr); + return (r); +} + +char reply_string[BUFSIZ]; /* last line of previous reply */ + +int +getreply(expecteof) + int expecteof; +{ + int c, n; + int dig; + int originalcode = 0, continuation = 0; + sig_t oldintr; + int pflag = 0; + char *cp, *pt = pasv; + + oldintr = signal(SIGINT, cmdabort); + for (;;) { + dig = n = code = 0; + cp = reply_string; + while ((c = getc(cin)) != '\n') { + if (c == IAC) { /* handle telnet commands */ + switch (c = getc(cin)) { + case WILL: + case WONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, DONT, c); + (void) fflush(cout); + break; + case DO: + case DONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, WONT, c); + (void) fflush(cout); + break; + default: + break; + } + continue; + } + dig++; + if (c == EOF) { + if (expecteof) { + (void) signal(SIGINT,oldintr); + code = 221; + return (0); + } + lostpeer(); + if (verbose) { + printf("421 Service not available, remote server has closed connection\n"); + (void) fflush(stdout); + } + code = 421; + return (4); + } + if (c != '\r' && (verbose > 0 || + (verbose > -1 && n == '5' && dig > 4))) { + if (proxflag && + (dig == 1 || dig == 5 && verbose == 0)) + printf("%s:",hostname); + (void) putchar(c); + } + if (dig < 4 && isdigit(c)) + code = code * 10 + (c - '0'); + if (!pflag && code == 227) + pflag = 1; + if (dig > 4 && pflag == 1 && isdigit(c)) + pflag = 2; + if (pflag == 2) { + if (c != '\r' && c != ')') + *pt++ = c; + else { + *pt = '\0'; + pflag = 3; + } + } + if (dig == 4 && c == '-') { + if (continuation) + code = 0; + continuation++; + } + if (n == 0) + n = c; + if (cp < &reply_string[sizeof(reply_string) - 1]) + *cp++ = c; + } + if (verbose > 0 || verbose > -1 && n == '5') { + (void) putchar(c); + (void) fflush (stdout); + } + if (continuation && code != originalcode) { + if (originalcode == 0) + originalcode = code; + continue; + } + *cp = '\0'; + if (n != '1') + cpend = 0; + (void) signal(SIGINT,oldintr); + if (code == 421 || originalcode == 421) + lostpeer(); + if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) + (*oldintr)(SIGINT); + return (n - '0'); + } +} + +int +empty(mask, sec) + struct fd_set *mask; + int sec; +{ + struct timeval t; + + t.tv_sec = (long) sec; + t.tv_usec = 0; + return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); +} + +jmp_buf sendabort; + +void +abortsend() +{ + + mflag = 0; + abrtflag = 0; + printf("\nsend aborted\nwaiting for remote to finish abort\n"); + (void) fflush(stdout); + longjmp(sendabort, 1); +} + +#define HASHBYTES 1024 + +void +sendrequest(cmd, local, remote, printnames) + char *cmd, *local, *remote; + int printnames; +{ + struct stat st; + struct timeval start, stop; + int c, d; + FILE *fin, *dout = 0, *popen(); + int (*closefunc) __P((FILE *)); + sig_t oldintr, oldintp; + long bytes = 0, hashbytes = HASHBYTES; + char *lmode, buf[BUFSIZ], *bufp; + + if (verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } + if (proxy) { + proxtrans(cmd, local, remote); + return; + } + if (curtype != type) + changetype(type, 0); + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + lmode = "w"; + if (setjmp(sendabort)) { + while (cpend) { + (void) getreply(0); + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (oldintr) + (void) signal(SIGINT,oldintr); + if (oldintp) + (void) signal(SIGPIPE,oldintp); + code = -1; + return; + } + oldintr = signal(SIGINT, abortsend); + if (strcmp(local, "-") == 0) + fin = stdin; + else if (*local == '|') { + oldintp = signal(SIGPIPE,SIG_IGN); + fin = popen(local + 1, "r"); + if (fin == NULL) { + warn("%s", local + 1); + (void) signal(SIGINT, oldintr); + (void) signal(SIGPIPE, oldintp); + code = -1; + return; + } + closefunc = pclose; + } else { + fin = fopen(local, "r"); + if (fin == NULL) { + warn("local: %s", local); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + closefunc = fclose; + if (fstat(fileno(fin), &st) < 0 || + (st.st_mode&S_IFMT) != S_IFREG) { + fprintf(stdout, "%s: not a plain file.\n", local); + (void) signal(SIGINT, oldintr); + fclose(fin); + code = -1; + return; + } + } + if (initconn()) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + code = -1; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + if (setjmp(sendabort)) + goto abort; + + if (restart_point && + (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { + int rc; + + switch (curtype) { + case TYPE_A: + rc = fseek(fin, (long) restart_point, SEEK_SET); + break; + case TYPE_I: + case TYPE_L: + rc = lseek(fileno(fin), restart_point, SEEK_SET); + break; + } + if (rc < 0) { + warn("local: %s", local); + restart_point = 0; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + if (command("REST %ld", (long) restart_point) + != CONTINUE) { + restart_point = 0; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + restart_point = 0; + lmode = "r+w"; + } + if (remote) { + if (command("%s %s", cmd, remote) != PRELIM) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + } else + if (command("%s", cmd) != PRELIM) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + dout = dataconn(lmode); + if (dout == NULL) + goto abort; + (void) gettimeofday(&start, (struct timezone *)0); + oldintp = signal(SIGPIPE, SIG_IGN); + switch (curtype) { + + case TYPE_I: + case TYPE_L: + errno = d = 0; + while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { + bytes += c; + for (bufp = buf; c > 0; c -= d, bufp += d) + if ((d = write(fileno(dout), bufp, c)) <= 0) + break; + if (hash) { + while (bytes >= hashbytes) { + (void) putchar('#'); + hashbytes += HASHBYTES; + } + (void) fflush(stdout); + } + } + if (hash && bytes > 0) { + if (bytes < HASHBYTES) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); + } + if (c < 0) + warn("local: %s", local); + if (d < 0) { + if (errno != EPIPE) + warn("netout"); + bytes = -1; + } + break; + + case TYPE_A: + while ((c = getc(fin)) != EOF) { + if (c == '\n') { + while (hash && (bytes >= hashbytes)) { + (void) putchar('#'); + (void) fflush(stdout); + hashbytes += HASHBYTES; + } + if (ferror(dout)) + break; + (void) putc('\r', dout); + bytes++; + } + (void) putc(c, dout); + bytes++; + /* if (c == '\r') { */ + /* (void) putc('\0', dout); // this violates rfc */ + /* bytes++; */ + /* } */ + } + if (hash) { + if (bytes < hashbytes) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); + } + if (ferror(fin)) + warn("local: %s", local); + if (ferror(dout)) { + if (errno != EPIPE) + warn("netout"); + bytes = -1; + } + break; + } + (void) gettimeofday(&stop, (struct timezone *)0); + if (closefunc != NULL) + (*closefunc)(fin); + (void) fclose(dout); + (void) getreply(0); + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); + return; +abort: + (void) gettimeofday(&stop, (struct timezone *)0); + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (!cpend) { + code = -1; + return; + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (dout) + (void) fclose(dout); + (void) getreply(0); + code = -1; + if (closefunc != NULL && fin != NULL) + (*closefunc)(fin); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); +} + +jmp_buf recvabort; + +void +abortrecv() +{ + + mflag = 0; + abrtflag = 0; + printf("\nreceive aborted\nwaiting for remote to finish abort\n"); + (void) fflush(stdout); + longjmp(recvabort, 1); +} + +void +recvrequest(cmd, local, remote, lmode, printnames) + char *cmd, *local, *remote, *lmode; + int printnames; +{ + FILE *fout, *din = 0; + int (*closefunc) __P((FILE *)); + sig_t oldintr, oldintp; + int c, d, is_retr, tcrflag, bare_lfs = 0; + static int bufsize; + static char *buf; + long bytes = 0, hashbytes = HASHBYTES; + struct timeval start, stop; + struct stat st; + + is_retr = strcmp(cmd, "RETR") == 0; + if (is_retr && verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } + if (proxy && is_retr) { + proxtrans(cmd, local, remote); + return; + } + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + tcrflag = !crflag && is_retr; + if (setjmp(recvabort)) { + while (cpend) { + (void) getreply(0); + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (oldintr) + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + oldintr = signal(SIGINT, abortrecv); + if (strcmp(local, "-") && *local != '|') { + if (access(local, 2) < 0) { + char *dir = strrchr(local, '/'); + + if (errno != ENOENT && errno != EACCES) { + warn("local: %s", local); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (dir != NULL) + *dir = 0; + d = access(dir ? local : ".", 2); + if (dir != NULL) + *dir = '/'; + if (d < 0) { + warn("local: %s", local); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (!runique && errno == EACCES && + chmod(local, 0600) < 0) { + warn("local: %s", local); + (void) signal(SIGINT, oldintr); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (runique && errno == EACCES && + (local = gunique(local)) == NULL) { + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + } + else if (runique && (local = gunique(local)) == NULL) { + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + } + if (!is_retr) { + if (curtype != TYPE_A) + changetype(TYPE_A, 0); + } else if (curtype != type) + changetype(type, 0); + if (initconn()) { + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (setjmp(recvabort)) + goto abort; + if (is_retr && restart_point && + command("REST %ld", (long) restart_point) != CONTINUE) + return; + if (remote) { + if (command("%s %s", cmd, remote) != PRELIM) { + (void) signal(SIGINT, oldintr); + return; + } + } else { + if (command("%s", cmd) != PRELIM) { + (void) signal(SIGINT, oldintr); + return; + } + } + din = dataconn("r"); + if (din == NULL) + goto abort; + if (strcmp(local, "-") == 0) + fout = stdout; + else if (*local == '|') { + oldintp = signal(SIGPIPE, SIG_IGN); + fout = popen(local + 1, "w"); + if (fout == NULL) { + warn("%s", local+1); + goto abort; + } + closefunc = pclose; + } else { + fout = fopen(local, lmode); + if (fout == NULL) { + warn("local: %s", local); + goto abort; + } + closefunc = fclose; + } + if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) + st.st_blksize = BUFSIZ; + if (st.st_blksize > bufsize) { + if (buf) + (void) free(buf); + buf = malloc((unsigned)st.st_blksize); + if (buf == NULL) { + warn("malloc"); + bufsize = 0; + goto abort; + } + bufsize = st.st_blksize; + } + (void) gettimeofday(&start, (struct timezone *)0); + switch (curtype) { + + case TYPE_I: + case TYPE_L: + if (restart_point && + lseek(fileno(fout), restart_point, SEEK_SET) < 0) { + warn("local: %s", local); + if (closefunc != NULL) + (*closefunc)(fout); + return; + } + errno = d = 0; + while ((c = read(fileno(din), buf, bufsize)) > 0) { + if ((d = write(fileno(fout), buf, c)) != c) + break; + bytes += c; + if (hash) { + while (bytes >= hashbytes) { + (void) putchar('#'); + hashbytes += HASHBYTES; + } + (void) fflush(stdout); + } + } + if (hash && bytes > 0) { + if (bytes < HASHBYTES) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); + } + if (c < 0) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (d < c) { + if (d < 0) + warn("local: %s", local); + else + warnx("%s: short write", local); + } + break; + + case TYPE_A: + if (restart_point) { + int i, n, ch; + + if (fseek(fout, 0L, SEEK_SET) < 0) + goto done; + n = restart_point; + for (i = 0; i++ < n;) { + if ((ch = getc(fout)) == EOF) + goto done; + if (ch == '\n') + i++; + } + if (fseek(fout, 0L, SEEK_CUR) < 0) { +done: + warn("local: %s", local); + if (closefunc != NULL) + (*closefunc)(fout); + return; + } + } + while ((c = getc(din)) != EOF) { + if (c == '\n') + bare_lfs++; + while (c == '\r') { + while (hash && (bytes >= hashbytes)) { + (void) putchar('#'); + (void) fflush(stdout); + hashbytes += HASHBYTES; + } + bytes++; + if ((c = getc(din)) != '\n' || tcrflag) { + if (ferror(fout)) + goto break2; + (void) putc('\r', fout); + if (c == '\0') { + bytes++; + goto contin2; + } + if (c == EOF) + goto contin2; + } + } + (void) putc(c, fout); + bytes++; + contin2: ; + } +break2: + if (bare_lfs) { + printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); + printf("File may not have transferred correctly.\n"); + } + if (hash) { + if (bytes < hashbytes) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); + } + if (ferror(din)) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (ferror(fout)) + warn("local: %s", local); + break; + } + if (closefunc != NULL) + (*closefunc)(fout); + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + (void) gettimeofday(&stop, (struct timezone *)0); + (void) fclose(din); + (void) getreply(0); + if (bytes > 0 && is_retr) + ptransfer("received", bytes, &start, &stop); + return; +abort: + +/* abort using RFC959 recommended IP,SYNC sequence */ + + (void) gettimeofday(&stop, (struct timezone *)0); + if (oldintp) + (void) signal(SIGPIPE, oldintr); + (void) signal(SIGINT, SIG_IGN); + if (!cpend) { + code = -1; + (void) signal(SIGINT, oldintr); + return; + } + + abort_remote(din); + code = -1; + if (data >= 0) { + (void) close(data); + data = -1; + } + if (closefunc != NULL && fout != NULL) + (*closefunc)(fout); + if (din) + (void) fclose(din); + if (bytes > 0) + ptransfer("received", bytes, &start, &stop); + (void) signal(SIGINT, oldintr); +} + +/* + * Need to start a listen on the data channel before we send the command, + * otherwise the server's connect may fail. + */ +int +initconn() +{ + char *p, *a; + int result, len, tmpno = 0; + int on = 1; + +noport: + data_addr = myctladdr; + if (sendport) + data_addr.sin_port = 0; /* let system pick one */ + if (data != -1) + (void) close(data); + data = socket(AF_INET, SOCK_STREAM, 0); + if (data < 0) { + warn("socket"); + if (tmpno) + sendport = 1; + return (1); + } + if (!sendport) + if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { + warn("setsockopt (reuse address)"); + goto bad; + } + if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { + warn("bind"); + goto bad; + } + if (options & SO_DEBUG && + setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) + warn("setsockopt (ignored)"); + len = sizeof (data_addr); + if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { + warn("getsockname"); + goto bad; + } + if (listen(data, 1) < 0) + warn("listen"); + if (sendport) { + a = (char *)&data_addr.sin_addr; + p = (char *)&data_addr.sin_port; +#define UC(b) (((int)b)&0xff) + result = + command("PORT %d,%d,%d,%d,%d,%d", + UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), + UC(p[0]), UC(p[1])); + if (result == ERROR && sendport == -1) { + sendport = 0; + tmpno = 1; + goto noport; + } + return (result != COMPLETE); + } + if (tmpno) + sendport = 1; +#ifdef IP_TOS + on = IPTOS_THROUGHPUT; + if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif + return (0); +bad: + (void) close(data), data = -1; + if (tmpno) + sendport = 1; + return (1); +} + +FILE * +dataconn(lmode) + char *lmode; +{ + struct sockaddr_in from; + int s, fromlen = sizeof (from), tos; + + s = accept(data, (struct sockaddr *) &from, &fromlen); + if (s < 0) { + warn("accept"); + (void) close(data), data = -1; + return (NULL); + } + (void) close(data); + data = s; +#ifdef IP_TOS + tos = IPTOS_THROUGHPUT; + if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif + return (fdopen(data, lmode)); +} + +void +ptransfer(direction, bytes, t0, t1) + char *direction; + long bytes; + struct timeval *t0, *t1; +{ + struct timeval td; + float s, bs; + + if (verbose) { + tvsub(&td, t1, t0); + s = td.tv_sec + (td.tv_usec / 1000000.); +#define nz(x) ((x) == 0 ? 1 : (x)) + bs = bytes / nz(s); + printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", + bytes, direction, s, bs / 1024.); + } +} + +/* +void +tvadd(tsum, t0) + struct timeval *tsum, *t0; +{ + + tsum->tv_sec += t0->tv_sec; + tsum->tv_usec += t0->tv_usec; + if (tsum->tv_usec > 1000000) + tsum->tv_sec++, tsum->tv_usec -= 1000000; +} +*/ + +void +tvsub(tdiff, t1, t0) + struct timeval *tdiff, *t1, *t0; +{ + + tdiff->tv_sec = t1->tv_sec - t0->tv_sec; + tdiff->tv_usec = t1->tv_usec - t0->tv_usec; + if (tdiff->tv_usec < 0) + tdiff->tv_sec--, tdiff->tv_usec += 1000000; +} + +void +psabort() +{ + + abrtflag++; +} + +void +pswitch(flag) + int flag; +{ + sig_t oldintr; + static struct comvars { + int connect; + char name[MAXHOSTNAMELEN]; + struct sockaddr_in mctl; + struct sockaddr_in hctl; + FILE *in; + FILE *out; + int tpe; + int curtpe; + int cpnd; + int sunqe; + int runqe; + int mcse; + int ntflg; + char nti[17]; + char nto[17]; + int mapflg; + char mi[MAXPATHLEN]; + char mo[MAXPATHLEN]; + } proxstruct, tmpstruct; + struct comvars *ip, *op; + + abrtflag = 0; + oldintr = signal(SIGINT, psabort); + if (flag) { + if (proxy) + return; + ip = &tmpstruct; + op = &proxstruct; + proxy++; + } else { + if (!proxy) + return; + ip = &proxstruct; + op = &tmpstruct; + proxy = 0; + } + ip->connect = connected; + connected = op->connect; + if (hostname) { + (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); + ip->name[strlen(ip->name)] = '\0'; + } else + ip->name[0] = 0; + hostname = op->name; + ip->hctl = hisctladdr; + hisctladdr = op->hctl; + ip->mctl = myctladdr; + myctladdr = op->mctl; + ip->in = cin; + cin = op->in; + ip->out = cout; + cout = op->out; + ip->tpe = type; + type = op->tpe; + ip->curtpe = curtype; + curtype = op->curtpe; + ip->cpnd = cpend; + cpend = op->cpnd; + ip->sunqe = sunique; + sunique = op->sunqe; + ip->runqe = runique; + runique = op->runqe; + ip->mcse = mcase; + mcase = op->mcse; + ip->ntflg = ntflag; + ntflag = op->ntflg; + (void) strncpy(ip->nti, ntin, 16); + (ip->nti)[strlen(ip->nti)] = '\0'; + (void) strcpy(ntin, op->nti); + (void) strncpy(ip->nto, ntout, 16); + (ip->nto)[strlen(ip->nto)] = '\0'; + (void) strcpy(ntout, op->nto); + ip->mapflg = mapflag; + mapflag = op->mapflg; + (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); + (ip->mi)[strlen(ip->mi)] = '\0'; + (void) strcpy(mapin, op->mi); + (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); + (ip->mo)[strlen(ip->mo)] = '\0'; + (void) strcpy(mapout, op->mo); + (void) signal(SIGINT, oldintr); + if (abrtflag) { + abrtflag = 0; + (*oldintr)(SIGINT); + } +} + +void +abortpt() +{ + + printf("\n"); + (void) fflush(stdout); + ptabflg++; + mflag = 0; + abrtflag = 0; + longjmp(ptabort, 1); +} + +void +proxtrans(cmd, local, remote) + char *cmd, *local, *remote; +{ + sig_t oldintr; + int secndflag = 0, prox_type, nfnd; + char *cmd2; + struct fd_set mask; + + if (strcmp(cmd, "RETR")) + cmd2 = "RETR"; + else + cmd2 = runique ? "STOU" : "STOR"; + if ((prox_type = type) == 0) { + if (unix_server && unix_proxy) + prox_type = TYPE_I; + else + prox_type = TYPE_A; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PASV") != COMPLETE) { + printf("proxy server does not support third party transfers.\n"); + return; + } + pswitch(0); + if (!connected) { + printf("No primary connection\n"); + pswitch(1); + code = -1; + return; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PORT %s", pasv) != COMPLETE) { + pswitch(1); + return; + } + if (setjmp(ptabort)) + goto abort; + oldintr = signal(SIGINT, abortpt); + if (command("%s %s", cmd, remote) != PRELIM) { + (void) signal(SIGINT, oldintr); + pswitch(1); + return; + } + sleep(2); + pswitch(1); + secndflag++; + if (command("%s %s", cmd2, local) != PRELIM) + goto abort; + ptflag++; + (void) getreply(0); + pswitch(0); + (void) getreply(0); + (void) signal(SIGINT, oldintr); + pswitch(1); + ptflag = 0; + printf("local: %s remote: %s\n", local, remote); + return; +abort: + (void) signal(SIGINT, SIG_IGN); + ptflag = 0; + if (strcmp(cmd, "RETR") && !proxy) + pswitch(1); + else if (!strcmp(cmd, "RETR") && proxy) + pswitch(0); + if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote((FILE *) NULL); + } + pswitch(1); + if (ptabflg) + code = -1; + (void) signal(SIGINT, oldintr); + return; + } + if (cpend) + abort_remote((FILE *) NULL); + pswitch(!proxy); + if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote((FILE *) NULL); + pswitch(1); + if (ptabflg) + code = -1; + (void) signal(SIGINT, oldintr); + return; + } + } + if (cpend) + abort_remote((FILE *) NULL); + pswitch(!proxy); + if (cpend) { + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + warn("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + if (proxy) + pswitch(0); + pswitch(1); + if (ptabflg) + code = -1; + (void) signal(SIGINT, oldintr); +} + +void +reset(argc, argv) + int argc; + char *argv[]; +{ + struct fd_set mask; + int nfnd = 1; + + FD_ZERO(&mask); + while (nfnd > 0) { + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,0)) < 0) { + warn("reset"); + code = -1; + lostpeer(); + } + else if (nfnd) { + (void) getreply(0); + } + } +} + +char * +gunique(local) + char *local; +{ + static char new[MAXPATHLEN]; + char *cp = strrchr(local, '/'); + int d, count=0; + char ext = '1'; + + if (cp) + *cp = '\0'; + d = access(cp ? local : ".", 2); + if (cp) + *cp = '/'; + if (d < 0) { + warn("local: %s", local); + return ((char *) 0); + } + (void) strcpy(new, local); + cp = new + strlen(new); + *cp++ = '.'; + while (!d) { + if (++count == 100) { + printf("runique: can't find unique file name.\n"); + return ((char *) 0); + } + *cp++ = ext; + *cp = '\0'; + if (ext == '9') + ext = '0'; + else + ext++; + if ((d = access(new, 0)) < 0) + break; + if (ext != '0') + cp--; + else if (*(cp - 2) == '.') + *(cp - 1) = '1'; + else { + *(cp - 2) = *(cp - 2) + 1; + cp--; + } + } + return (new); +} + +void +abort_remote(din) + FILE *din; +{ + char buf[BUFSIZ]; + int nfnd; + struct fd_set mask; + + /* + * send IAC in urgent mode instead of DM because 4.3BSD places oob mark + * after urgent byte rather than before as is protocol now + */ + sprintf(buf, "%c%c%c", IAC, IP, IAC); + if (send(fileno(cout), buf, 3, MSG_OOB) != 3) + warn("abort"); + fprintf(cout,"%cABOR\r\n", DM); + (void) fflush(cout); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if (din) { + FD_SET(fileno(din), &mask); + } + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + warn("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + if (din && FD_ISSET(fileno(din), &mask)) { + while (read(fileno(din), buf, BUFSIZ) > 0) + /* LOOP */; + } + if (getreply(0) == ERROR && code == 552) { + /* 552 needed for nic style abort */ + (void) getreply(0); + } + (void) getreply(0); +} diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h new file mode 100644 index 0000000..3a0d1bc --- /dev/null +++ b/usr.bin/ftp/ftp_var.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1985, 1989, 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. + * + * @(#)ftp_var.h 8.3 (Berkeley) 4/2/94 + */ + +/* + * FTP global variables. + */ + +#include +#include + +#include "extern.h" + +/* + * Options and other state info. + */ +int trace; /* trace packets exchanged */ +int hash; /* print # for each buffer transferred */ +int sendport; /* use PORT cmd for each data connection */ +int verbose; /* print messages coming back from server */ +int connected; /* connected to server */ +int fromatty; /* input is from a terminal */ +int interactive; /* interactively prompt on m* cmds */ +int debug; /* debugging level */ +int bell; /* ring bell on cmd completion */ +int doglob; /* glob local file names */ +int autologin; /* establish user account on connection */ +int proxy; /* proxy server connection active */ +int proxflag; /* proxy connection exists */ +int sunique; /* store files on server with unique name */ +int runique; /* store local files with unique name */ +int mcase; /* map upper to lower case for mget names */ +int ntflag; /* use ntin ntout tables for name translation */ +int mapflag; /* use mapin mapout templates on file names */ +int code; /* return/reply code for ftp command */ +int crflag; /* if 1, strip car. rets. on ascii gets */ +char pasv[64]; /* passive port for proxy data connection */ +char *altarg; /* argv[1] with no shell-like preprocessing */ +char ntin[17]; /* input translation table */ +char ntout[17]; /* output translation table */ +char mapin[MAXPATHLEN]; /* input map template */ +char mapout[MAXPATHLEN]; /* output map template */ +char typename[32]; /* name of file transfer type */ +int type; /* requested file transfer type */ +int curtype; /* current file transfer type */ +char structname[32]; /* name of file transfer structure */ +int stru; /* file transfer structure */ +char formname[32]; /* name of file transfer format */ +int form; /* file transfer format */ +char modename[32]; /* name of file transfer mode */ +int mode; /* file transfer mode */ +char bytename[32]; /* local byte size in ascii */ +int bytesize; /* local byte size in binary */ + +char *hostname; /* name of host connected to */ +int unix_server; /* server is unix, can use binary for ascii */ +int unix_proxy; /* proxy is unix, can use binary for ascii */ + +struct servent *sp; /* service spec for tcp/ftp */ + +jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ + +char line[200]; /* input line buffer */ +char *stringbase; /* current scan point in line buffer */ +char argbuf[200]; /* argument storage buffer */ +char *argbase; /* current storage point in arg buffer */ +int margc; /* count of arguments on input line */ +char *margv[20]; /* args parsed from input line */ +int cpend; /* flag: if != 0, then pending server reply */ +int mflag; /* flag: if != 0, then active multi command */ + +int options; /* used during socket creation */ + +/* + * Format of command table. + */ +struct cmd { + char *c_name; /* name of command */ + char *c_help; /* help string */ + char c_bell; /* give bell when command completes */ + char c_conn; /* must be connected to use command */ + char c_proxy; /* proxy server may execute */ + void (*c_handler) __P((int, char **)); /* function to call */ +}; + +struct macel { + char mac_name[9]; /* macro name */ + char *mac_start; /* start of macro in macbuf */ + char *mac_end; /* end of macro in macbuf */ +}; + +int macnum; /* number of defined macros */ +struct macel macros[16]; +char macbuf[4096]; diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c new file mode 100644 index 0000000..37fa85b --- /dev/null +++ b/usr.bin/ftp/main.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 1985, 1989, 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 copyright[] = +"@(#) Copyright (c) 1985, 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/3/94"; +#endif /* not lint */ + +/* + * FTP User Program -- Command Interface. + */ +/*#include */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, top; + struct passwd *pw = NULL; + char *cp, homedir[MAXPATHLEN]; + + sp = getservbyname("ftp", "tcp"); + if (sp == 0) + errx(1, "ftp/tcp: unknown service"); + doglob = 1; + interactive = 1; + autologin = 1; + + while ((ch = getopt(argc, argv, "dgintv")) != EOF) { + switch (*cp) { + case 'd': + options |= SO_DEBUG; + debug++; + break; + + case 'g': + doglob = 0; + break; + + case 'i': + interactive = 0; + break; + + case 'n': + autologin = 0; + break; + + case 't': + trace++; + break; + + case 'v': + verbose++; + break; + + default: + (void)fprintf(stderr, + "usage: ftp [-dgintv] [host [port]]\n"); + exit(1); + } + } + argc -= optind; + argv += optind; + + fromatty = isatty(fileno(stdin)); + if (fromatty) + verbose++; + cpend = 0; /* no pending replies */ + proxy = 0; /* proxy not active */ + crflag = 1; /* strip c.r. on ascii gets */ + sendport = -1; /* not using ports */ + /* + * Set up the home directory in case we're globbing. + */ + cp = getlogin(); + if (cp != NULL) { + pw = getpwnam(cp); + } + if (pw == NULL) + pw = getpwuid(getuid()); + if (pw != NULL) { + home = homedir; + (void) strcpy(home, pw->pw_dir); + } + if (argc > 0) { + char *xargv[5]; + extern char *__progname; + + if (setjmp(toplevel)) + exit(0); + (void) signal(SIGINT, intr); + (void) signal(SIGPIPE, lostpeer); + xargv[0] = __progname; + xargv[1] = argv[0]; + xargv[2] = argv[1]; + xargv[3] = argv[2]; + xargv[4] = NULL; + setpeer(argc+1, xargv); + } + top = setjmp(toplevel) == 0; + if (top) { + (void) signal(SIGINT, intr); + (void) signal(SIGPIPE, lostpeer); + } + for (;;) { + cmdscanner(top); + top = 1; + } +} + +void +intr() +{ + + longjmp(toplevel, 1); +} + +void +lostpeer() +{ + + if (connected) { + if (cout != NULL) { + (void) shutdown(fileno(cout), 1+1); + (void) fclose(cout); + cout = NULL; + } + if (data >= 0) { + (void) shutdown(data, 1+1); + (void) close(data); + data = -1; + } + connected = 0; + } + pswitch(1); + if (connected) { + if (cout != NULL) { + (void) shutdown(fileno(cout), 1+1); + (void) fclose(cout); + cout = NULL; + } + connected = 0; + } + proxflag = 0; + pswitch(0); +} + +/* +char * +tail(filename) + char *filename; +{ + char *s; + + while (*filename) { + s = strrchr(filename, '/'); + if (s == NULL) + break; + if (s[1]) + return (s + 1); + *s = '\0'; + } + return (filename); +} +*/ + +/* + * Command parser. + */ +void +cmdscanner(top) + int top; +{ + struct cmd *c; + int l; + + if (!top) + (void) putchar('\n'); + for (;;) { + if (fromatty) { + printf("ftp> "); + (void) fflush(stdout); + } + if (fgets(line, sizeof line, stdin) == NULL) + quit(0, 0); + l = strlen(line); + if (l == 0) + break; + if (line[--l] == '\n') { + if (l == 0) + break; + line[l] = '\0'; + } else if (l == sizeof(line) - 2) { + printf("sorry, input line too long\n"); + while ((l = getchar()) != '\n' && l != EOF) + /* void */; + break; + } /* else it was a line without a newline */ + makeargv(); + if (margc == 0) { + continue; + } + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + if (c->c_conn && !connected) { + printf("Not connected.\n"); + continue; + } + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) + (void) putchar('\007'); + if (c->c_handler != help) + break; + } + (void) signal(SIGINT, intr); + (void) signal(SIGPIPE, lostpeer); +} + +struct cmd * +getcmd(name) + char *name; +{ + char *p, *q; + struct cmd *c, *found; + int nmatches, longest; + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; p = c->c_name; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); +} + +/* + * Slice a string up into argc/argv. + */ + +int slrflag; + +void +makeargv() +{ + char **argp; + + margc = 0; + argp = margv; + stringbase = line; /* scan from first of buffer */ + argbase = argbuf; /* store from first of buffer */ + slrflag = 0; + while (*argp++ = slurpstring()) + margc++; +} + +/* + * Parse string into argbuf; + * implemented with FSM to + * handle quoting and strings + */ +char * +slurpstring() +{ + int got_one = 0; + char *sb = stringbase; + char *ap = argbase; + char *tmp = argbase; /* will return this if token found */ + + if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ + switch (slrflag) { /* and $ as token for macro invoke */ + case 0: + slrflag++; + stringbase++; + return ((*sb == '!') ? "!" : "$"); + /* NOTREACHED */ + case 1: + slrflag++; + altarg = stringbase; + break; + default: + break; + } + } + +S0: + switch (*sb) { + + case '\0': + goto OUT; + + case ' ': + case '\t': + sb++; goto S0; + + default: + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = sb; + break; + default: + break; + } + goto S1; + } + +S1: + switch (*sb) { + + case ' ': + case '\t': + case '\0': + goto OUT; /* end of token */ + + case '\\': + sb++; goto S2; /* slurp next character */ + + case '"': + sb++; goto S3; /* slurp quoted string */ + + default: + *ap++ = *sb++; /* add character to token */ + got_one = 1; + goto S1; + } + +S2: + switch (*sb) { + + case '\0': + goto OUT; + + default: + *ap++ = *sb++; + got_one = 1; + goto S1; + } + +S3: + switch (*sb) { + + case '\0': + goto OUT; + + case '"': + sb++; goto S1; + + default: + *ap++ = *sb++; + got_one = 1; + goto S3; + } + +OUT: + if (got_one) + *ap++ = '\0'; + argbase = ap; /* update storage pointer */ + stringbase = sb; /* update scan pointer */ + if (got_one) { + return (tmp); + } + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = (char *) 0; + break; + default: + break; + } + return ((char *)0); +} + +#define HELPINDENT ((int) sizeof ("directory")) + +/* + * Help command. + * Call each command handler with argc == 0 and argv[0] == name. + */ +void +help(argc, argv) + int argc; + char *argv[]; +{ + struct cmd *c; + + if (argc == 1) { + int i, j, w, k; + int columns, width = 0, lines; + + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { + int len = strlen(c->c_name); + + if (len > width) + width = len; + } + width = (width + 8) &~ 7; + columns = 80 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + for (j = 0; j < columns; j++) { + c = cmdtab + j * lines + i; + if (c->c_name && (!proxy || c->c_proxy)) { + printf("%s", c->c_name); + } + else if (c->c_name) { + for (k=0; k < strlen(c->c_name); k++) { + (void) putchar(' '); + } + } + if (c + lines >= &cmdtab[NCMDS]) { + printf("\n"); + break; + } + w = strlen(c->c_name); + while (w < width) { + w = (w + 8) &~ 7; + (void) putchar('\t'); + } + } + } + return; + } + while (--argc > 0) { + char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%-*s\t%s\n", HELPINDENT, + c->c_name, c->c_help); + } +} diff --git a/usr.bin/ftp/pathnames.h b/usr.bin/ftp/pathnames.h new file mode 100644 index 0000000..be72b7e --- /dev/null +++ b/usr.bin/ftp/pathnames.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#undef _PATH_TMP +#define _PATH_TMP "/tmp/ftpXXXXXX" diff --git a/usr.bin/ftp/ruserpass.c b/usr.bin/ftp/ruserpass.c new file mode 100644 index 0000000..07bb1f4 --- /dev/null +++ b/usr.bin/ftp/ruserpass.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 1985, 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[] = "@(#)ruserpass.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +static int token __P((void)); +static FILE *cfile; + +#define DEFAULT 1 +#define LOGIN 2 +#define PASSWD 3 +#define ACCOUNT 4 +#define MACDEF 5 +#define ID 10 +#define MACH 11 + +static char tokval[100]; + +static struct toktab { + char *tokstr; + int tval; +} toktab[]= { + { "default", DEFAULT }, + { "login", LOGIN }, + { "password", PASSWD }, + { "passwd", PASSWD }, + { "account", ACCOUNT }, + { "machine", MACH }, + { "macdef", MACDEF }, + { NULL, 0 } +}; + +int +ruserpass(host, aname, apass, aacct) + char *host, **aname, **apass, **aacct; +{ + char *hdir, buf[BUFSIZ], *tmp; + char myname[MAXHOSTNAMELEN], *mydomain; + int t, i, c, usedefault = 0; + struct stat stb; + + hdir = getenv("HOME"); + if (hdir == NULL) + hdir = "."; + (void) sprintf(buf, "%s/.netrc", hdir); + cfile = fopen(buf, "r"); + if (cfile == NULL) { + if (errno != ENOENT) + warn("%s", buf); + return (0); + } + if (gethostname(myname, sizeof(myname)) < 0) + myname[0] = '\0'; + if ((mydomain = strchr(myname, '.')) == NULL) + mydomain = ""; +next: + while ((t = token())) switch(t) { + + case DEFAULT: + usedefault = 1; + /* FALL THROUGH */ + + case MACH: + if (!usedefault) { + if (token() != ID) + continue; + /* + * Allow match either for user's input host name + * or official hostname. Also allow match of + * incompletely-specified host in local domain. + */ + if (strcasecmp(host, tokval) == 0) + goto match; + if (strcasecmp(hostname, tokval) == 0) + goto match; + if ((tmp = strchr(hostname, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(hostname, tokval, tmp-hostname) == 0 && + tokval[tmp - hostname] == '\0') + goto match; + if ((tmp = strchr(host, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(host, tokval, tmp - host) == 0 && + tokval[tmp - host] == '\0') + goto match; + continue; + } + match: + while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { + + case LOGIN: + if (token()) + if (*aname == 0) { + *aname = malloc((unsigned) strlen(tokval) + 1); + (void) strcpy(*aname, tokval); + } else { + if (strcmp(*aname, tokval)) + goto next; + } + break; + case PASSWD: + if (strcmp(*aname, "anonymous") && + fstat(fileno(cfile), &stb) >= 0 && + (stb.st_mode & 077) != 0) { + warnx("Error: .netrc file is readable by others."); + warnx("Remove password or make file unreadable by others."); + goto bad; + } + if (token() && *apass == 0) { + *apass = malloc((unsigned) strlen(tokval) + 1); + (void) strcpy(*apass, tokval); + } + break; + case ACCOUNT: + if (fstat(fileno(cfile), &stb) >= 0 + && (stb.st_mode & 077) != 0) { + warnx("Error: .netrc file is readable by others."); + warnx("Remove account or make file unreadable by others."); + goto bad; + } + if (token() && *aacct == 0) { + *aacct = malloc((unsigned) strlen(tokval) + 1); + (void) strcpy(*aacct, tokval); + } + break; + case MACDEF: + if (proxy) { + (void) fclose(cfile); + return (0); + } + while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t'); + if (c == EOF || c == '\n') { + printf("Missing macdef name argument.\n"); + goto bad; + } + if (macnum == 16) { + printf("Limit of 16 macros have already been defined\n"); + goto bad; + } + tmp = macros[macnum].mac_name; + *tmp++ = c; + for (i=0; i < 8 && (c=getc(cfile)) != EOF && + !isspace(c); ++i) { + *tmp++ = c; + } + if (c == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + *tmp = '\0'; + if (c != '\n') { + while ((c=getc(cfile)) != EOF && c != '\n'); + } + if (c == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + if (macnum == 0) { + macros[macnum].mac_start = macbuf; + } + else { + macros[macnum].mac_start = macros[macnum-1].mac_end + 1; + } + tmp = macros[macnum].mac_start; + while (tmp != macbuf + 4096) { + if ((c=getc(cfile)) == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + *tmp = c; + if (*tmp == '\n') { + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + break; + } + *tmp = '\0'; + } + tmp++; + } + if (tmp == macbuf + 4096) { + printf("4K macro buffer exceeded\n"); + goto bad; + } + break; + default: + warnx("Unknown .netrc keyword %s", tokval); + break; + } + goto done; + } +done: + (void) fclose(cfile); + return (0); +bad: + (void) fclose(cfile); + return (-1); +} + +static int +token() +{ + char *cp; + int c; + struct toktab *t; + + if (feof(cfile) || ferror(cfile)) + return (0); + while ((c = getc(cfile)) != EOF && + (c == '\n' || c == '\t' || c == ' ' || c == ',')) + continue; + if (c == EOF) + return (0); + cp = tokval; + if (c == '"') { + while ((c = getc(cfile)) != EOF && c != '"') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } else { + *cp++ = c; + while ((c = getc(cfile)) != EOF + && c != '\n' && c != '\t' && c != ' ' && c != ',') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } + *cp = 0; + if (tokval[0] == 0) + return (0); + for (t = toktab; t->tokstr; t++) + if (!strcmp(t->tokstr, tokval)) + return (t->tval); + return (ID); +} diff --git a/usr.bin/gcore/Makefile b/usr.bin/gcore/Makefile new file mode 100644 index 0000000..c7bf6e0 --- /dev/null +++ b/usr.bin/gcore/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= gcore +SRCS= gcore.c md-${MACHINE}.c +LDADD= -lkvm + +.include diff --git a/usr.bin/gcore/extern.h b/usr.bin/gcore/extern.h new file mode 100644 index 0000000..3dccafe --- /dev/null +++ b/usr.bin/gcore/extern.h @@ -0,0 +1,37 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +void err __P((int, const char *, ...)); +void md_core __P((kvm_t *, int, struct kinfo_proc *)); diff --git a/usr.bin/gcore/gcore.1 b/usr.bin/gcore/gcore.1 new file mode 100644 index 0000000..42fddbc --- /dev/null +++ b/usr.bin/gcore/gcore.1 @@ -0,0 +1,90 @@ +.\" Copyright (c) 1983, 1990, 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. +.\" +.\" @(#)gcore.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd "April 18, 1994" +.Dt GCORE 1 +.Os BSD 4.2 +.Sh NAME +.Nm gcore +.Nd get core images of running process +.Sh SYNOPSIS +.Nm gcore +.Op Fl s +.Op Fl c Ar core +.Ar exec pid +.Sh DESCRIPTION +.Nm Gcore +creates a core image of the specified process, +suitable for use with +.Xr gdb 1 . +By default, the core is written to the file +.Dq Pa core. . +Both the executable image, +.Ar exec , +and the process identifier, +.Ar pid , +must be given on the command line. +.Pp +The options are: +.Bl -tag -width indent +.It Fl c +Write the core file to the specified file instead of +.Dq Pa core. . +.It Fl s +Stop the process while gathering the core image, and resume it +when done. This guarantees that the resulting core dump will +be in a consistent state. The process is resumed even if it was +already stopped. +The same effect can be achieved manually with +.Xr kill 1 . +.El +.Sh FILES +.Bl -tag -width /var/log/messages -compact +.It Pa core. +The core image. +.EL +.Dp +.Sh HISTORY +.Nm Gcore +appeared in 4.2BSD. +.Sh BUGS +Context switches or paging activity that occur while +.Nm gcore +is running may cause the program to become confused. +For best results, use -s to temporarily stop the target process. +.Pp +.Nm Gcore +is not compatible with the original 4.2BSD version. +In particular, 4.4BSD requires the +.Ar exec +argument. diff --git a/usr.bin/gcore/gcore.c b/usr.bin/gcore/gcore.c new file mode 100644 index 0000000..2ecca18 --- /dev/null +++ b/usr.bin/gcore/gcore.c @@ -0,0 +1,313 @@ +/*- + * 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 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[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; +#endif /* not lint */ + +/* + * Originally written by Eric Cooper in Fall 1981. + * Inspired by a version 6 program by Len Levin, 1978. + * Several pieces of code lifted from Bill Joy's 4BSD ps. + * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, + * Lawrence Berkeley Laboratory. + * + * Portions of this software were developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA + * contract BG 91-66 and contributed to Berkeley. + */ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +void core __P((int, int, struct kinfo_proc *)); +void datadump __P((int, int, struct proc *, u_long, int)); +void usage __P((void)); +void userdump __P((int, struct proc *, u_long, int)); + +kvm_t *kd; +/* XXX undocumented routine, should be in kvm.h? */ +ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t)); + +static int data_offset; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register struct proc *p; + struct kinfo_proc *ki; + struct exec exec; + int ch, cnt, efd, fd, pid, sflag, uid; + char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; + + sflag = 0; + corefile = NULL; + while ((ch = getopt(argc, argv, "c:s")) != EOF) { + switch (ch) { + case 'c': + corefile = optarg; + break; + case 's': + sflag = 1; + break; + default: + usage(); + break; + } + } + argv += optind; + argc -= optind; + + if (argc != 2) + usage(); + + kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); + if (kd == NULL) + err(1, "%s", errbuf); + + uid = getuid(); + pid = atoi(argv[1]); + + ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); + if (ki == NULL || cnt != 1) + err(1, "%d: not found", pid); + + p = &ki->kp_proc; + if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) + err(1, "%d: not owner", pid); + + if (p->p_stat == SZOMB) + err(1, "%d: zombie", pid); + + if (p->p_flag & P_WEXIT) + err(0, "process exiting"); + if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ + err(1, "%d: system process"); + + if (corefile == NULL) { + (void)snprintf(fname, sizeof(fname), "core.%d", pid); + corefile = fname; + } + fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); + if (fd < 0) + err(1, "%s: %s\n", corefile, strerror(errno)); + + efd = open(argv[0], O_RDONLY, 0); + if (efd < 0) + err(1, "%s: %s\n", argv[0], strerror(errno)); + + cnt = read(efd, &exec, sizeof(exec)); + if (cnt != sizeof(exec)) + err(1, "%s exec header: %s", + argv[0], cnt > 0 ? strerror(EIO) : strerror(errno)); + + data_offset = N_DATOFF(exec); + + if (sflag && kill(pid, SIGSTOP) < 0) + err(0, "%d: stop signal: %s", pid, strerror(errno)); + + core(efd, fd, ki); + + if (sflag && kill(pid, SIGCONT) < 0) + err(0, "%d: continue signal: %s", pid, strerror(errno)); + (void)close(fd); + + exit(0); +} + +/* + * core -- + * Build the core file. + */ +void +core(efd, fd, ki) + int efd; + int fd; + struct kinfo_proc *ki; +{ + union { + struct user user; + char ubytes[ctob(UPAGES)]; + } uarea; + struct proc *p = &ki->kp_proc; + int tsize = ki->kp_eproc.e_vm.vm_tsize; + int dsize = ki->kp_eproc.e_vm.vm_dsize; + int ssize = ki->kp_eproc.e_vm.vm_ssize; + int cnt; + + /* Read in user struct */ + cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea)); + if (cnt != sizeof(uarea)) + err(1, "read user structure: %s", + cnt > 0 ? strerror(EIO) : strerror(errno)); + + /* + * Fill in the eproc vm parameters, since these are garbage unless + * the kernel is dumping core or something. + */ + uarea.user.u_kproc = *ki; + + /* Dump user area */ + cnt = write(fd, &uarea, sizeof(uarea)); + if (cnt != sizeof(uarea)) + err(1, "write user structure: %s", + cnt > 0 ? strerror(EIO) : strerror(errno)); + + /* Dump data segment */ + datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize); + + /* Dump stack segment */ + userdump(fd, p, USRSTACK - ctob(ssize), ssize); + + /* Dump machine dependent portions of the core. */ + md_core(kd, fd, ki); +} + +void +datadump(efd, fd, p, addr, npage) + register int efd; + register int fd; + struct proc *p; + register u_long addr; + register int npage; +{ + register int cc, delta; + char buffer[NBPG]; + + delta = data_offset - addr; + while (--npage >= 0) { + cc = kvm_uread(kd, p, addr, buffer, NBPG); + if (cc != NBPG) { + /* Try to read the page from the executable. */ + if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) + err(1, "seek executable: %s", strerror(errno)); + cc = read(efd, buffer, sizeof(buffer)); + if (cc != sizeof(buffer)) + if (cc < 0) + err(1, "read executable: %s", + strerror(errno)); + else /* Assume untouched bss page. */ + bzero(buffer, sizeof(buffer)); + } + cc = write(fd, buffer, NBPG); + if (cc != NBPG) + err(1, "write data segment: %s", + cc > 0 ? strerror(EIO) : strerror(errno)); + addr += NBPG; + } +} + +void +userdump(fd, p, addr, npage) + register int fd; + struct proc *p; + register u_long addr; + register int npage; +{ + register int cc; + char buffer[NBPG]; + + while (--npage >= 0) { + cc = kvm_uread(kd, p, addr, buffer, NBPG); + if (cc != NBPG) + /* Could be an untouched fill-with-zero page. */ + bzero(buffer, NBPG); + cc = write(fd, buffer, NBPG); + if (cc != NBPG) + err(1, "write stack segment: %s", + cc > 0 ? strerror(EIO) : strerror(errno)); + addr += NBPG; + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(int fatal, const char *fmt, ...) +#else +err(fatal, fmt, va_alist) + int fatal; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "gcore: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/gcore/md-nop.c b/usr.bin/gcore/md-nop.c new file mode 100644 index 0000000..46e90c4 --- /dev/null +++ b/usr.bin/gcore/md-nop.c @@ -0,0 +1,53 @@ +/*- + * 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[] = "@(#)md-nop.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include "extern.h" + +void +md_core(kd, fd, ki) + kvm_t *kd; + int fd; + struct kinfo_proc *ki; +{ + /* Don't need to fix anything for this architecture. */ + return; +} diff --git a/usr.bin/gcore/md-sparc.c b/usr.bin/gcore/md-sparc.c new file mode 100644 index 0000000..794ceb1 --- /dev/null +++ b/usr.bin/gcore/md-sparc.c @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)md-sparc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "extern.h" + +#ifndef offsetof +#define offsetof(s, f) ((int)&((s *)0)->f) +#endif + +static void +shift_page(fd, off, ssize) + register int fd; + register off_t off; + register int ssize; +{ + char buffer[NBPG]; + + (void)lseek(fd, (off_t)-NBPG, SEEK_END); + for (; ssize > 0; ssize -= NBPG) { + (void)read(fd, buffer, NBPG); + (void)write(fd, buffer, NBPG); + (void)lseek(fd, (off_t)-2 * NBPG, SEEK_CUR); + } +} + +/* + * Fix up the core image for the sparc. We need to flush any register + * windows that are cached in the pcb out to the user stack. + * Also, we need to get the trap frame and possible floating point state + * from the top of the kernel stack and store it in the pcb. + */ +void +md_core(kd, fd, ki) + kvm_t *kd; + int fd; + struct kinfo_proc *ki; +{ + register struct rwindow *rw; + register int nsaved, cc, ssize; + register off_t off, s; + register u_long sp; + struct pcb pcb; + struct trapframe tf; + + /* + * Before anything else read the trapframe. Synchronizing here + * is impossible if the process is running. + */ + cc = kvm_read(kd, (u_long)ki->kp_proc.p_md.md_tf, + /* XXX */ + (void *)&tf, sizeof(tf)); + if (cc < 0) + err(1, "kvm_read: %s (reading kernel trapframe)", + kvm_geterr(kd)); + if (cc != sizeof(tf)) + err(1, "cannot read kernel trapframe"); + + /* + * Write out the real trap frame. + */ + off = offsetof(struct user, u_md); + off += offsetof(struct md_coredump, md_tf); + if (lseek(fd, off, SEEK_SET) == -1) + err(1, "lseek: %s", strerror(errno)); + (void)write(fd, &tf, sizeof(tf)); + + if (ki->kp_proc.p_md.md_fpstate != 0) { + /* + * If floating point state is present, write it out too. + * It comes right after the trapframe so we don't need to seek. + */ + struct fpstate fs; + cc = kvm_read(kd, (u_long)ki->kp_proc.p_md.md_fpstate, + (void *)&fs, sizeof(fs)); + if (cc < 0) + err(1, "kvm_read: %s (fpu state)", kvm_geterr(kd)); + if (cc != sizeof(fs)) + err(1, "cannot read fpu state"); + (void)write(fd, (char *)&fs, sizeof(fs)); + } + /* + * Read pcb. + */ + if (lseek(fd, (off_t)offsetof(struct user, u_pcb), SEEK_SET) == -1) + err(1, "lseek: %s", strerror(errno)); + cc = read(fd, (char *)&pcb, sizeof(pcb)); + if (cc != sizeof(pcb)) { + if (cc < 0) + err(1, "read: %s", strerror(errno)); + err(1, "couldn't read pcb from core file"); + } + + /* + * Write any unsaved windows to the appropriate stack locations. + */ + nsaved = pcb.pcb_nsaved; + if (nsaved == 0) + return; + + rw = &pcb.pcb_rw[0]; + off = ctob(UPAGES + ki->kp_eproc.e_vm.vm_dsize); + ssize = ctob(ki->kp_eproc.e_vm.vm_ssize); + sp = tf.tf_out[6]; + for (; --nsaved >= 0; ++rw) { + /* + * Copy register window into appropriate stack location. + */ + s = ssize - (USRSTACK - sp); + if (s < 0) { + if (s < -NBPG) + err(1, "cannot copy pcb windows to stack"); + /* + * It's possible to be missing the bottomost + * page because a stack page hasn't been allocated + * for the register save area. Shift over + * the stack segment by a page, and update + * the u-area to reflect the new stack size. YECH! + */ + shift_page(fd, off, ssize); + ssize += NBPG; + s += NBPG; + ++ki->kp_eproc.e_vm.vm_ssize; + (void)lseek(fd, + (off_t)offsetof(struct user, u_kproc.kp_eproc.e_vm), + SEEK_SET); + (void)write(fd, + &ki->kp_eproc.e_vm, sizeof(ki->kp_eproc.e_vm)); + } + if (lseek(fd, off + s, SEEK_SET) == -1) + err(1, "cannot copy pcb windows to stack"); + + (void)write(fd, rw, sizeof(*rw)); + sp = rw->rw_in[6]; + } +} diff --git a/usr.bin/gprof/Makefile b/usr.bin/gprof/Makefile new file mode 100644 index 0000000..0762b78 --- /dev/null +++ b/usr.bin/gprof/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/29/93 + +PROG= gprof +SRCS= gprof.c arcs.c dfn.c lookup.c ${MACHINE}.c hertz.c \ + printgprof.c printlist.c + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m 444 \ + ${.CURDIR}/gprof.flat ${.CURDIR}/gprof.callg \ + ${DESTDIR}/usr/share/misc + +.include diff --git a/usr.bin/gprof/PSD.doc/Makefile b/usr.bin/gprof/PSD.doc/Makefile new file mode 100644 index 0000000..12f9c39 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 8/14/93 + +DIR= psd/18.gprof +SRCS= header.me abstract.me intro.me profiling.me gathering.me \ + postp.me present.me refs.me +DPADD= postp1.pic postp2.pic postp3.pic pres1.pic pres2.pic +MACROS= -me + +paper.ps: ${SRCS} ${DPADD} + ${SOELIM} ${SRCS} | ${PIC} | ${TBL} | ${EQN} | ${ROFF} > ${.TARGET} + +.include diff --git a/usr.bin/gprof/PSD.doc/abstract.me b/usr.bin/gprof/PSD.doc/abstract.me new file mode 100644 index 0000000..28e8066 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/abstract.me @@ -0,0 +1,66 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)abstract.me 8.1 (Berkeley) 6/8/93 +.\" +.sp 1 +\fB\s+2gprof: a Call Graph Execution Profiler\s-2\fP\** +.(f +\**This work was supported by grant MCS80-05144 +from the National Science Foundation. +.)f +.sp 1 +by +\fISusan L. Graham\fP +\fIPeter B. Kessler\fP +\fIMarshall K. McKusick\fP +.sp 1 +Computer Science Division +Electrical Engineering and Computer Science Department +University of California, Berkeley +Berkeley, California 94720 +.ce 0 +.sp 1 +.sp 0.5i +.sh 0 "Abstract" +.pp +Large complex programs are composed of many small routines +that implement abstractions for the routines that call them. +To be useful, an execution profiler must attribute +execution time in a way that is significant for the +logical structure of a program +as well as for its textual decomposition. +This data must then be displayed to the user +in a convenient and informative way. +The \fBgprof\fP profiler +accounts for the running time of called routines +in the running time of the routines that call them. +The design and use of this profiler is described. diff --git a/usr.bin/gprof/PSD.doc/gathering.me b/usr.bin/gprof/PSD.doc/gathering.me new file mode 100644 index 0000000..17130c3 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/gathering.me @@ -0,0 +1,231 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)gathering.me 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Gathering Profile Data" +.pp +Routine calls or statement executions can be measured by having a +compiler augment the code at strategic points. +The additions can be inline increments to counters [Knuth71] +[Satterthwaite72] [Joy79] or calls to +monitoring routines [Unix]. +The counter increment overhead is low, and is suitable for +profiling statements. +A call of the monitoring routine has an overhead comparable with a +call of a regular routine, and is therefore only suited +to profiling on a routine by routine basis. +However, the monitoring routine solution has certain advantages. +Whatever counters are needed by the monitoring routine can be +managed by the monitoring routine itself, rather than being +distributed around the code. +In particular, a monitoring routine can easily be called from separately +compiled programs. +In addition, different monitoring routines can be linked into the +program +being measured +to assemble different profiling data without having to +change the compiler or recompile the program. +We have exploited this approach; +our compilers for C, Fortran77, and Pascal can insert calls to a +monitoring routine in the prologue for each routine. +Use of the monitoring routine requires no planning on part of a +programmer other than to request that augmented routine +prologues be produced during compilation. +.pp +We are interested in gathering three pieces of information during +program execution: call counts and execution times for +each profiled routine, and the arcs of the dynamic call graph +traversed by this execution of the program. +By post-processing of this data we can build the dynamic call +graph for this execution of the program and propagate times along +the edges of this graph to attribute times for routines to the +routines that invoke them. +.pp +Gathering of the profiling information should not greatly +interfere with the running of the program. +Thus, the monitoring routine must not produce trace output each +time it is invoked. +The volume of data thus produced would be unmanageably large, +and the time required to record it would overwhelm the running +time of most programs. +Similarly, the monitoring routine can not do the analysis of +the profiling data (e.g. assembling the call graph, propagating +times around it, discovering cycles, etc.) during program +execution. +Our solution is to gather profiling data in memory during program +execution and to condense it to a file as the profiled +program exits. +This file is then processed by a separate program to produce the +listing of the profile data. +An advantage of this approach is that the profile data for +several executions of a program can be combined by the +post-processing to provide a profile of many +executions. +.pp +The execution time monitoring consists of three parts. +The first part allocates and initializes the runtime monitoring data +structures before the program begins execution. +The second part is the monitoring routine invoked from the +prologue of each profiled routine. +The third part condenses the data structures and writes them +to a file as the program terminates. +The monitoring routine is discussed in detail in the following sections. +.sh 2 "Execution Counts" +.pp +The \fBgprof\fP monitoring routine counts the number of times +each profiled routine is called. +The monitoring routine also records the arc in the call graph +that activated the profiled routine. +The count is associated with the arc in the call graph +rather than with the routine. +Call counts for routines can then be determined by summing the counts +on arcs directed into that routine. +In a machine-dependent fashion, the monitoring routine notes its +own return address. +This address is in the prologue of some profiled routine that is +the destination of an arc in the dynamic call graph. +The monitoring routine also discovers the return address for that +routine, thus identifying the call site, or source of the arc. +The source of the arc is in the \fIcaller\fP, and the destination is in +the \fIcallee\fP. +For example, if a routine A calls a routine B, A is the caller, +and B is the callee. +The prologue of B will include a call to the monitoring routine +that will note the arc from A to B and either initialize or +increment a counter for that arc. +.pp +One can not afford to have the monitoring routine output tracing +information as each arc is identified. +Therefore, the monitoring routine maintains a table of all the +arcs discovered, with counts of the numbers of times each is +traversed during execution. +This table is accessed once per routine call. +Access to it +must be as fast as possible so as not to overwhelm the time +required to execute the program. +.pp +Our solution is to access the table through a hash table. +We use the call site as the primary key with the callee +address being the secondary key. +Since each call site typically calls only one callee, we can +reduce (usually to one) the number of minor lookups based on the callee. +Another alternative would use the callee as the primary key and the +call site as the secondary key. +Such an organization has the advantage of associating callers with +callees, at the expense of longer lookups in the monitoring +routine. +We are fortunate to be running in a virtual memory environment, +and (for the sake of speed) were able to allocate enough space +for the primary hash table to allow a one-to-one mapping from +call site addresses to the primary hash table. +Thus our hash function is trivial to calculate and collisions +occur only for call sites that call multiple +destinations (e.g. functional parameters and functional variables). +A one level hash function using both call site and callee would +result in an unreasonably large hash table. +Further, the number of dynamic call sites and callees is not known during +execution of the profiled program. +.pp +Not all callers and callees can be identified by the monitoring +routine. +Routines that were compiled without the profiling augmentations +will not call the monitoring routine as part of their prologue, +and thus no arcs will be recorded whose destinations are in these +routines. +One need not profile all the routines in a program. +Routines that are not profiled run at full speed. +Certain routines, notably exception handlers, are invoked by +non-standard calling sequences. +Thus the monitoring routine may know the destination of an arc +(the callee), +but find it difficult or +impossible to determine the source of the arc (the caller). +Often in these cases the apparent source of the arc is not a call +site at all. +Such anomalous invocations are declared ``spontaneous''. +.sh 2 "Execution Times" +.pp +The execution times for routines can be gathered in at least two +ways. +One method measures the execution time of a routine by measuring +the elapsed time from routine entry to routine exit. +Unfortunately, time measurement is complicated on time-sharing +systems by the time-slicing of the program. +A second method samples the value of the program counter at some +interval, and infers execution time from the distribution of the +samples within the program. +This technique is particularly suited to time-sharing systems, +where the time-slicing can serve as the basis for sampling +the program counter. +Notice that, whereas the first method could provide exact timings, +the second is inherently a statistical approximation. +.pp +The sampling method need not require support from the operating +system: all that is needed is the ability to set and respond to +``alarm clock'' interrupts that run relative to program time. +It is imperative that the intervals be uniform since the +sampling of the program counter rather than the duration of the +interval is the basis of the distribution. +If sampling is done too often, the interruptions to sample the +program counter will overwhelm the running of the profiled program. +On the other hand, the program must run for enough sampled +intervals that the distribution of the samples accurately +represents the distribution of time for the execution of the +program. +As with routine call tracing, the monitoring routine can not +afford to output information for each program counter +sample. +In our computing environment, the operating system can provide a +histogram of the location of the program counter at the end of +each clock tick (1/60th of a second) in which a program runs. +The histogram is assembled in memory as the program runs. +This facility is enabled by our monitoring routine. +We have adjusted the granularity of the histogram so that +program counter values map one-to-one onto the histogram. +We make the simplifying assumption that all calls to a specific +routine require the same amount of time to execute. +This assumption may disguise that some calls +(or worse, some call sites) always invoke a routine +such that its execution is faster (or slower) +than the average time for that routine. +.pp +When the profiled program terminates, +the arc table and the histogram of +program counter samples is written to a file. +The arc table is condensed to consist of the source and destination +addresses of the arc and the count of the number of times the arc +was traversed by this execution of the program. +The recorded histogram consists of counters of the number of +times the program counter was found to be in each of the ranges covered +by the histogram. +The ranges themselves are summarized as a +lower and upper bound and a step size. diff --git a/usr.bin/gprof/PSD.doc/header.me b/usr.bin/gprof/PSD.doc/header.me new file mode 100644 index 0000000..aef606d --- /dev/null +++ b/usr.bin/gprof/PSD.doc/header.me @@ -0,0 +1,38 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)header.me 8.1 (Berkeley) 8/14/93 +.\" +.\"he 'gprof''Graham, Kessler, McKusick' +.\"fo 'Draft of \*(td''%' +.\"ls 2 +.eh 'PSD:18-%''gprof \*- a Call Graph Execution Profiler' +.oh 'gprof \*- A Call Graph Execution Profiler''PSD:18-%' diff --git a/usr.bin/gprof/PSD.doc/intro.me b/usr.bin/gprof/PSD.doc/intro.me new file mode 100644 index 0000000..3a872b2 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/intro.me @@ -0,0 +1,81 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)intro.me 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Programs to be Profiled" +.pp +Software research environments +normally include many large programs +both for production use and for experimental investigation. +These programs are typically modular, +in accordance with generally accepted principles +of good program design. +Often they consist of numerous small routines +that implement various abstractions. +Sometimes such large programs are written +by one programmer +who has understood the requirements for +these abstractions, and has programmed them +appropriately. +More frequently the program has +had multiple authors and has +evolved over time, changing the demands placed +on the implementation of the abstractions without +changing the implementation itself. +Finally, the program may be assembled from a library +of abstraction implementations +unexamined by the programmer. +.pp +Once a large program is executable, +it is often desirable to increase its speed, +especially if small portions of the program +are found to dominate its execution time. +The purpose of the \fBgprof\fP profiling tool is to +help the user evaluate alternative implementations +of abstractions. +We developed this tool in response to our efforts +to improve a code generator we were writing [Graham82]. +.pp +The \fBgprof\fP design takes advantage of the fact that the programs +to be measured are large, structured and hierarchical. +We provide a profile in which the execution time +for a set of routines that implement an +abstraction is collected and charged +to that abstraction. +The profile can be used to compare and assess the costs of +various implementations. +.pp +The profiler can be linked into a program without +special planning by the programmer. +The overhead for using \fBgprof\fP is low; +both in terms of added execution time and in the +volume of profiling information recorded. diff --git a/usr.bin/gprof/PSD.doc/postp.me b/usr.bin/gprof/PSD.doc/postp.me new file mode 100644 index 0000000..d71fefb --- /dev/null +++ b/usr.bin/gprof/PSD.doc/postp.me @@ -0,0 +1,190 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)postp.me 8.1 (Berkeley) 6/8/93 +.\" +.EQ +delim $$ +gsize 11 +.EN +.sh 1 "Post Processing" +.pp +Having gathered the arcs of the call graph and timing information +for an execution of the program, +we are interested in attributing the time for each routine to the +routines that call it. +We build a dynamic call graph with arcs from caller to callee, +and propagate time from descendants to ancestors +by topologically sorting the call graph. +Time propagation is performed from the leaves of the +call graph toward the roots, according to the order +assigned by a topological numbering algorithm. +The topological numbering ensures that +all edges in the graph go from higher numbered nodes to lower +numbered nodes. +An example is given in Figure 1. +If we propagate time from nodes in the +order assigned by the algorithm, +execution time can be propagated from descendants to ancestors +after a single traversal of each arc in the call graph. +Each parent receives some fraction of a child's time. +Thus time is charged to the +caller in addition to being charged to the callee. +.(z +.so postp1.pic +.ce 2 +Topological ordering +Figure 1. +.ce 0 +.)z +.pp +Let $C sub e$ be the number of calls to some routine, +$e$, and $C sub e sup r$ be the number of +calls from a caller $r$ to a callee $e$. +Since we are assuming each call to a routine takes the +average amount of time for all calls to that routine, +the caller is accountable for +$C sub e sup r / C sub e$ +of the time spent by the callee. +Let the $S sub e$ be the $selftime$ of a routine, $e$. +The selftime of a routine can be determined from the +timing information gathered during profiled program execution. +The total time, $T sub r$, we wish to account to a routine +$r$, is then given by the recurrence equation: +.EQ +T sub r ~ = ~ {S sub r} ~ + ~ + sum from {r ~ roman CALLS ~ e} + {T sub e times {{C sub e sup r} over {C sub e}}} +.EN +where $r ~ roman CALLS ~ e$ is a relation showing all routines +$e$ called by a routine $r$. +This relation is easily available from the call graph. +.pp +However, if the execution contains recursive calls, +the call graph has cycles that +cannot be topologically sorted. +In these cases, we discover strongly-connected +components in the call graph, +treat each such component as a single node, +and then sort the resulting graph. +We use a variation of Tarjan's strongly-connected +components algorithm +that discovers strongly-connected components as it is assigning +topological order numbers [Tarjan72]. +.pp +Time propagation within strongly connected +components is a problem. +For example, a self-recursive routine +(a trivial cycle in the call graph) +is accountable for all the time it +uses in all its recursive instantiations. +In our scheme, this time should be +shared among its call graph parents. +The arcs from a routine to itself are of interest, +but do not participate in time propagation. +Thus the simple equation for time propagation +does not work within strongly connected components. +Time is not propagated from one member of a cycle to another, +since, by definition, this involves propagating time from a routine +to itself. +In addition, children of one member of a cycle +must be considered children of all members of the cycle. +Similarly, parents of one member of the cycle must inherit +all members of the cycle as descendants. +It is for these reasons that we collapse connected components. +Our solution collects all members of a cycle together, +summing the time and call counts for all members. +All calls into the cycle are made to share the total +time of the cycle, and all descendants of the cycle +propagate time into the cycle as a whole. +Calls among the members of the cycle +do not propagate any time, +though they are listed in the call graph profile. +.pp +Figure 2 shows a modified version of the call graph of Figure 1, +in which the nodes labelled 3 and 7 in Figure 1 are mutually +recursive. +The topologically sorted graph after the cycle is collapsed is +given in Figure 3. +.(z +.so postp2.pic +.ce 2 +Cycle to be collapsed. +Figure 2. +.ce 0 +.)z +.(z +.so postp3.pic +.ce 2 +Topological numbering after cycle collapsing. +Figure 3. +.ce 0 +.)z +.pp +Since the technique described above only collects the +dynamic call graph, +and the program typically does not call every routine +on each execution, +different executions can introduce different cycles in the +dynamic call graph. +Since cycles often have a significant effect on time propagation, +it is desirable to incorporate the static call graph so that cycles +will have the same members regardless of how the program runs. +.pp +The static call graph can be constructed from the source text +of the program. +However, discovering the static call graph from the source text +would require two moderately difficult steps: +finding the source text for the program +(which may not be available), +and scanning and parsing that text, +which may be in any one of several languages. +.pp +In our programming system, +the static calling information is also contained in the +executable version of the program, +which we already have available, +and which is in language-independent form. +One can examine the instructions +in the object program, +looking for calls to routines, and note which +routines can be called. +This technique allows us to add arcs to those already in the +dynamic call graph. +If a statically discovered arc already exists in the dynamic call +graph, no action is required. +Statically discovered arcs that do not exist in the dynamic call +graph are added to the graph with a traversal count of zero. +Thus they are never responsible for any time propagation. +However, they may affect the structure of the graph. +Since they may complete strongly connected components, +the static call graph construction is +done before topological ordering. diff --git a/usr.bin/gprof/PSD.doc/postp1.pic b/usr.bin/gprof/PSD.doc/postp1.pic new file mode 100644 index 0000000..1446092 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/postp1.pic @@ -0,0 +1,54 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)postp1.pic 8.1 (Berkeley) 6/8/93 +.\" +.PS +circle diam .3i "8" +circle diam .3i "9" at 1st circle + (2i,0i) +circle diam .3i "3" at 1st circle + (0.5i,-0.5i) +circle diam .3i "7" at 2nd circle - (0.5i, 0.5i) +circle diam .3i "2" at 1st circle - (0i,1i) +circle diam .3i "5" at 5th circle + (1i,0i) +circle diam .3i "6" at 2nd circle - (0i,1i) +circle diam .3i "1" at 3rd circle - (0i,1i) +circle diam .3i "4" at 4th circle - (0i,1i) +arrow from 1st circle to 3rd circle chop .15i chop .15i +arrow from 1st circle to 4th circle chop .15i chop .15i +arrow from 2nd circle to 4th circle chop .15i chop .15i +arrow from 3rd circle to 5th circle chop .15i chop .15i +arrow from 4th circle to 5th circle chop .15i chop .15i +arrow from 4th circle to 6th circle chop .15i chop .15i +arrow from 4th circle to 7th circle chop .15i chop .15i +arrow from 5th circle to 8th circle chop .15i chop .15i +arrow from 6th circle to 8th circle chop .15i chop .15i +arrow from 6th circle to 9th circle chop .15i chop .15i +.PE diff --git a/usr.bin/gprof/PSD.doc/postp2.pic b/usr.bin/gprof/PSD.doc/postp2.pic new file mode 100644 index 0000000..3b31736 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/postp2.pic @@ -0,0 +1,56 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)postp2.pic 8.1 (Berkeley) 6/8/93 +.\" +.PS +circle diam .3i "\(ci" +circle diam .3i "\(ci" at 1st circle + (2i,0i) +circle diam .3i "\(bu" at 1st circle + (0.5i,-0.5i) +circle diam .3i "\(bu" at 2nd circle - (0.5i, 0.5i) +circle diam .3i "\(ci" at 1st circle - (0i,1i) +circle diam .3i "\(ci" at 5th circle + (1i,0i) +circle diam .3i "\(ci" at 2nd circle - (0i,1i) +circle diam .3i "\(ci" at 3rd circle - (0i,1i) +circle diam .3i "\(ci" at 4th circle - (0i,1i) +arrow from 1st circle to 3rd circle chop .15i chop .15i +arrow from 1st circle to 4th circle chop .15i chop .15i +arrow from 2nd circle to 4th circle chop .15i chop .15i +spline -> from 3rd circle right .5i up .075i then right .5i down .075i chop .15i chop .15i +spline -> from 4th circle left .5i down .075i then left .5i up .075i chop .15i chop .15i +arrow from 3rd circle to 5th circle chop .15i chop .15i +arrow from 4th circle to 5th circle chop .15i chop .15i +arrow from 4th circle to 6th circle chop .15i chop .15i +arrow from 4th circle to 7th circle chop .15i chop .15i +arrow from 5th circle to 8th circle chop .15i chop .15i +arrow from 6th circle to 8th circle chop .15i chop .15i +arrow from 6th circle to 9th circle chop .15i chop .15i +.PE diff --git a/usr.bin/gprof/PSD.doc/postp3.pic b/usr.bin/gprof/PSD.doc/postp3.pic new file mode 100644 index 0000000..65eb2a7 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/postp3.pic @@ -0,0 +1,51 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)postp3.pic 8.1 (Berkeley) 6/8/93 +.\" +.PS +circle diam .3i "7" +circle diam .3i "8" at 1st circle + (2i,0i) +EL: ellipse wid 1i ht .3i "\fB6\fR\h'.7i'\fB6\fR" at 1st circle + (1i,-0.5i) +circle diam .3i "2" at 1st circle - (0i,1i) +circle diam .3i "4" at 3th circle + (1i,0i) +circle diam .3i "5" at 2nd circle - (0i,1i) +circle diam .3i "1" at 3rd circle + (0.5i,-0.5i) +circle diam .3i "3" at 5th circle - (0.5i,0.5i) +arrow from 1st circle to EL.nw chop .15i chop 0i +arrow from 2nd circle to EL.ne chop .15i chop 0i +arrow from EL.sw to 3rd circle chop 0i chop .15i +arrow from EL.s to 4th circle chop 0i chop .15i +arrow from EL.se to 5th circle chop 0i chop .15i +arrow from 3rd circle to 6th circle chop .15i chop .15i +arrow from 4th circle to 6th circle chop .15i chop .15i +arrow from 4th circle to 7th circle chop .15i chop .15i +.PE diff --git a/usr.bin/gprof/PSD.doc/pres1.pic b/usr.bin/gprof/PSD.doc/pres1.pic new file mode 100644 index 0000000..0c311a1 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/pres1.pic @@ -0,0 +1,56 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)pres1.pic 8.1 (Berkeley) 6/8/93 +.\" +.PS +ellipse ht .3i wid .75i "\s-1CALLER1\s+1" +ellipse ht .3i wid .75i "\s-1CALLER2\s+1" at 1st ellipse + (2i,0i) +ellipse ht .3i wid .8i "\s-1EXAMPLE\s+1" at 1st ellipse + (1i,-.5i) +ellipse ht .3i wid .5i "\s-1SUB1\s+1" at 1st ellipse - (0i,1i) +ellipse ht .3i wid .5i "\s-1SUB2\s+1" at 3rd ellipse - (0i,.5i) +ellipse ht .3i wid .5i "\s-1SUB3\s+1" at 2nd ellipse - (0i,1i) +line <- from 1st ellipse up .5i left .5i chop .1875i +line <- from 1st ellipse up .5i right .5i chop .1875i +line <- from 2nd ellipse up .5i left .5i chop .1875i +line <- from 2nd ellipse up .5i right .5i chop .1875i +arrow from 1st ellipse to 3rd ellipse chop +arrow from 2nd ellipse to 3rd ellipse chop +arrow from 3rd ellipse to 4th ellipse chop +arrow from 3rd ellipse to 5th ellipse chop .15i chop .15i +arrow from 3rd ellipse to 6th ellipse chop +arrow from 4th ellipse down .5i left .5i chop .1875i +arrow from 4th ellipse down .5i right .5i chop .1875i +arrow from 5th ellipse down .5i left .5i chop .1875i +arrow from 5th ellipse down .5i right .5i chop .1875i +arrow from 6th ellipse down .5i left .5i chop .1875i +arrow from 6th ellipse down .5i right .5i chop .1875i +.PE diff --git a/usr.bin/gprof/PSD.doc/pres2.pic b/usr.bin/gprof/PSD.doc/pres2.pic new file mode 100644 index 0000000..c3a4ea0 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/pres2.pic @@ -0,0 +1,52 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)pres2.pic 8.1 (Berkeley) 6/8/93 +.\" +.PS +ellipse ht .3i wid .6i "\s-1CALC1\s+1" +ellipse ht .3i wid .6i "\s-1CALC2\s+1" at 1st ellipse + (.75i,0i) +ellipse ht .3i wid .6i "\s-1CALC3\s+1" at 1st ellipse + (1.5i,0i) +ellipse ht .3i wid .8i "\s-1FORMAT1\s+1" at 1st ellipse - (0i,.5i) +ellipse ht .3i wid .8i "\s-1FORMAT2\s+1" at 3rd ellipse - (0i,.5i) +ellipse ht .3i wid .75i "\s-1\"WRITE\"\s+1" at 5th ellipse - (.75i,.5i) +line <- from 1st ellipse up .5i left .4i chop .1825i +line <- from 1st ellipse up .5i right .4i chop .1825i +line <- from 2nd ellipse up .5i left .4i chop .1825i +line <- from 2nd ellipse up .5i right .4i chop .1825i +line <- from 3rd ellipse up .5i left .4i chop .1825i +line <- from 3rd ellipse up .5i right .4i chop .1825i +arrow from 1st ellipse to 4th ellipse chop .15i +arrow from 2nd ellipse to 5th ellipse chop +arrow from 3rd ellipse to 5th ellipse chop .15i +arrow from 4th ellipse to 6th ellipse chop +arrow from 5th ellipse to 6th ellipse chop +.PE diff --git a/usr.bin/gprof/PSD.doc/present.me b/usr.bin/gprof/PSD.doc/present.me new file mode 100644 index 0000000..1dd7f62 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/present.me @@ -0,0 +1,306 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)present.me 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Data Presentation" +.pp +The data is presented to the user in two different formats. +The first presentation simply lists the routines +without regard to the amount of time their descendants use. +The second presentation incorporates the call graph of the +program. +.sh 2 "The Flat Profile +.pp +The flat profile consists of a list of all the routines +that are called during execution of the program, +with the count of the number of times they are called +and the number of seconds of execution time for which they +are themselves accountable. +The routines are listed in decreasing order of execution time. +A list of the routines that are never called during execution of +the program is also available +to verify that nothing important is omitted by +this execution. +The flat profile gives a quick overview of the routines that are used, +and shows the routines that are themselves responsible +for large fractions of the execution time. +In practice, +this profile usually shows that no single function +is overwhelmingly responsible for +the total time of the program. +Notice that for this profile, +the individual times sum to the total execution time. +.sh 2 "The Call Graph Profile" +.sz 10 +.(z +.TS +box center; +c c c c c l l +c c c c c l l +c c c c c l l +l n n n c l l. + called/total \ \ parents +index %time self descendants called+self name index + called/total \ \ children +_ + 0.20 1.20 4/10 \ \ \s-1CALLER1\s+1 [7] + 0.30 1.80 6/10 \ \ \s-1CALLER2\s+1 [1] +[2] 41.5 0.50 3.00 10+4 \s-1EXAMPLE\s+1 [2] + 1.50 1.00 20/40 \ \ \s-1SUB1\s+1 [4] + 0.00 0.50 1/5 \ \ \s-1SUB2\s+1 [9] + 0.00 0.00 0/5 \ \ \s-1SUB3\s+1 [11] +.TE +.ce 2 +Profile entry for \s-1EXAMPLE\s+1. +Figure 4. +.)z +.pp +Ideally, we would like to print the call graph of the program, +but we are limited by the two-dimensional nature of our output +devices. +We cannot assume that a call graph is planar, +and even if it is, that we can print a planar version of it. +Instead, we choose to list each routine, +together with information about +the routines that are its direct parents and children. +This listing presents a window into the call graph. +Based on our experience, +both parent information and child information +is important, +and should be available without searching +through the output. +.pp +The major entries of the call graph profile are the entries from the +flat profile, augmented by the time propagated to each +routine from its descendants. +This profile is sorted by the sum of the time for the routine +itself plus the time inherited from its descendants. +The profile shows which of the higher level routines +spend large portions of the total execution time +in the routines that they call. +For each routine, we show the amount of time passed by each child +to the routine, which includes time for the child itself +and for the descendants of the child +(and thus the descendants of the routine). +We also show the percentage these times represent of the total time +accounted to the child. +Similarly, the parents of each routine are listed, +along with time, +and percentage of total routine time, +propagated to each one. +.pp +Cycles are handled as single entities. +The cycle as a whole is shown as though it were a single routine, +except that members of the cycle are listed in place of the children. +Although the number of calls of each member +from within the cycle are shown, +they do not affect time propagation. +When a child is a member of a cycle, +the time shown is the appropriate fraction of the time +for the whole cycle. +Self-recursive routines have their calls broken +down into calls from the outside and self-recursive calls. +Only the outside calls affect the propagation of time. +.pp +The following example is a typical fragment of a call graph. +.(b +.so pres1.pic +.)b +The entry in the call graph profile listing for this example is +shown in Figure 4. +.pp +The entry is for routine \s-1EXAMPLE\s+1, which has +the Caller routines as its parents, +and the Sub routines as its children. +The reader should keep in mind that all information +is given \fIwith respect to \s-1EXAMPLE\s+1\fP. +The index in the first column shows that \s-1EXAMPLE\s+1 +is the second entry in the profile listing. +The \s-1EXAMPLE\s+1 routine is called ten times, four times by \s-1CALLER1\s+1, +and six times by \s-1CALLER2\s+1. +Consequently 40% of \s-1EXAMPLE\s+1's time is propagated to \s-1CALLER1\s+1, +and 60% of \s-1EXAMPLE\s+1's time is propagated to \s-1CALLER2\s+1. +The self and descendant fields of the parents +show the amount of self and descendant time \s-1EXAMPLE\s+1 +propagates to them (but not the time used by +the parents directly). +Note that \s-1EXAMPLE\s+1 calls itself recursively four times. +The routine \s-1EXAMPLE\s+1 calls routine \s-1SUB1\s+1 twenty times, \s-1SUB2\s+1 once, +and never calls \s-1SUB3\s+1. +Since \s-1SUB2\s+1 is called a total of five times, +20% of its self and descendant time is propagated to \s-1EXAMPLE\s+1's +descendant time field. +Because \s-1SUB1\s+1 is a member of \fIcycle 1\fR, +the self and descendant times +and call count fraction +are those for the cycle as a whole. +Since cycle 1 is called a total of forty times +(not counting calls among members of the cycle), +it propagates 50% of the cycle's self and descendant +time to \s-1EXAMPLE\s+1's descendant time field. +Finally each name is followed by an index that shows +where on the listing to find the entry for that routine. +.sh 1 "Using the Profiles" +.pp +The profiler is a useful tool for improving +a set of routines that implement an abstraction. +It can be helpful in identifying poorly coded routines, +and in evaluating the new algorithms and code that replace them. +Taking full advantage of the profiler +requires a careful examination of the call graph profile, +and a thorough knowledge of the abstractions underlying +the program. +.pp +The easiest optimization that can be performed +is a small change +to a control construct or data structure that improves the +running time of the program. +An obvious starting point +is a routine that is called many times. +For example, suppose an output +routine is the only parent +of a routine that formats the data. +If this format routine is expanded inline in the +output routine, the overhead of a function call and +return can be saved for each datum that needs to be formatted. +.pp +The drawback to inline expansion is that the data abstractions +in the program may become less parameterized, +hence less clearly defined. +The profiling will also become less useful since the loss of +routines will make its output more granular. +For example, +if the symbol table functions ``lookup'', ``insert'', and ``delete'' +are all merged into a single parameterized routine, +it will be impossible to determine the costs +of any one of these individual functions from the profile. +.pp +Further potential for optimization lies in routines that +implement data abstractions whose total execution +time is long. +For example, a lookup routine might be called only a few +times, but use an inefficient linear search algorithm, +that might be replaced with a binary search. +Alternately, the discovery that a rehashing function is being +called excessively, can lead to a different +hash function or a larger hash table. +If the data abstraction function cannot easily be speeded up, +it may be advantageous to cache its results, +and eliminate the need to rerun +it for identical inputs. +These and other ideas for program improvement are discussed in +[Bentley81]. +.pp +This tool is best used in an iterative approach: +profiling the program, +eliminating one bottleneck, +then finding some other part of the program +that begins to dominate execution time. +For instance, we have used \fBgprof\fR on itself; +eliminating, rewriting, and inline expanding routines, +until reading +data files (hardly a target for optimization!) +represents the dominating factor in its execution time. +.pp +Certain types of programs are not easily analyzed by \fBgprof\fR. +They are typified by programs that exhibit a large degree of +recursion, such as recursive descent compilers. +The problem is that most of the major routines are grouped +into a single monolithic cycle. +As in the symbol table abstraction that is placed +in one routine, +it is impossible to distinguish which members of the cycle are +responsible for the execution time. +Unfortunately there are no easy modifications to these programs that +make them amenable to analysis. +.pp +A completely different use of the profiler is to analyze the control +flow of an unfamiliar program. +If you receive a program from another user that you need to modify +in some small way, +it is often unclear where the changes need to be made. +By running the program on an example and then using \fBgprof\fR, +you can get a view of the structure of the program. +.pp +Consider an example in which you need to change the output format +of the program. +For purposes of this example suppose that the call graph +of the output portion of the program has the following structure: +.(b +.so pres2.pic +.)b +Initially you look through the \fBgprof\fR +output for the system call ``\s-1WRITE\s+1''. +The format routine you will need to change is probably +among the parents of the ``\s-1WRITE\s+1'' procedure. +The next step is to look at the profile entry for each +of parents of ``\s-1WRITE\s+1'', +in this example either ``\s-1FORMAT1\s+1'' or ``\s-1FORMAT2\s+1'', +to determine which one to change. +Each format routine will have one or more parents, +in this example ``\s-1CALC1\s+1'', ``\s-1CALC2\s+1'', and ``\s-1CALC3\s+1''. +By inspecting the source code for each of these routines +you can determine which format routine generates the output that +you wish to modify. +Since the \fBgprof\fR entry shows all the +potential calls to the format routine you intend to change, +you can determine if your modifications will affect output that +should be left alone. +If you desire to change the output of ``\s-1CALC2\s+1'', but not ``\s-1CALC3\s+1'', +then formatting routine ``\s-1FORMAT2\s+1'' needs to be split +into two separate routines, +one of which implements the new format. +You can then retarget just the call by ``\s-1CALC2\s+1'' +that needs the new format. +It should be noted that the static call information is particularly +useful here since the test case you run probably will not +exercise the entire program. +.sh 1 "Conclusions" +.pp +We have created a profiler that aids in the evaluation +of modular programs. +For each routine in the program, +the profile shows the extent to which that routine +helps support various abstractions, +and how that routine uses other abstractions. +The profile accurately assesses the cost of routines +at all levels of the program decomposition. +The profiler is easily used, +and can be compiled into the program without any prior planning by +the programmer. +It adds only five to thirty percent execution overhead to the program +being profiled, +produces no additional output until after the program finishes, +and allows the program to be measured in its actual environment. +Finally, the profiler runs on a time-sharing system +using only the normal services provided by the operating system +and compilers. diff --git a/usr.bin/gprof/PSD.doc/profiling.me b/usr.bin/gprof/PSD.doc/profiling.me new file mode 100644 index 0000000..227aedf --- /dev/null +++ b/usr.bin/gprof/PSD.doc/profiling.me @@ -0,0 +1,115 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)profiling.me 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Types of Profiling" +.pp +There are several different uses for program profiles, +and each may require different information from the profiles, +or different presentation of the information. +We distinguish two broad categories of profiles: +those that present counts of statement or routine invocations, +and those that display timing information about statements +or routines. +Counts are typically presented in tabular form, +often in parallel with a listing of the source code. +Timing information could be similarly presented; +but more than one measure of time might be associated with each +statement or routine. +For example, +in the framework used by \fBgprof\fP +each profiled segment would display two times: +one for the time used by the segment itself, and another for the +time inherited from code segments it invokes. +.pp +Execution counts are used in many different contexts. +The exact number of times a routine or statement is activated +can be used to determine if an algorithm is performing as +expected. +Cursory inspection of such counters may show algorithms whose +complexity is unsuited to the task at hand. +Careful interpretation of counters can often suggest +improvements to acceptable algorithms. +Precise examination can uncover subtle errors in an +algorithm. +At this level, profiling counters are similar to +debugging statements whose purpose is to show the number of times +a piece of code is executed. +Another view of such counters is as boolean values. +One may be interested that a portion of code has executed at +all, for exhaustive testing, or to check that one implementation +of an abstraction completely replaces a previous one. +.pp +Execution counts are not necessarily proportional to the amount +of time required to execute the routine or statement. +Further, the execution time of a routine will not be the same for +all calls on the routine. +The criteria for establishing execution time +must be decided. +If a routine implements an abstraction by invoking other abstractions, +the time spent in the routine will not accurately reflect the +time required by the abstraction it implements. +Similarly, if an abstraction is implemented by several +routines the time required by the abstraction will be distributed +across those routines. +.pp +Given the execution time of individual routines, +\fBgprof\fP accounts to each routine the time spent +for it by the routines it invokes. +This accounting is done by assembling a \fIcall graph\fP with nodes that +are the routines of the program and directed arcs that represent +calls from call sites to routines. +We distinguish among three different call graphs for a program. +The \fIcomplete call graph\fP incorporates all routines and all +potential arcs, +including arcs that represent calls to functional parameters +or functional variables. +This graph contains the other two graphs as subgraphs. +The \fIstatic call graph\fP includes all routines and all possible arcs +that are not calls to functional parameters or variables. +The \fIdynamic call graph\fP includes only those routines and +arcs traversed by the profiled execution of the program. +This graph need not include all routines, nor need it include all +potential arcs between the routines it covers. +It may, however, include arcs to functional parameters or +variables that the static call graph may omit. +The static call graph can be determined from the (static) program text. +The dynamic call graph is determined only by profiling an +execution of the program. +The complete call graph for a monolithic program could be determined +by data flow analysis techniques. +The complete call graph for programs that change +during execution, by modifying themselves or dynamically loading +or overlaying code, may never be determinable. +Both the static call graph and the dynamic call graph are used +by \fBgprof\fP, but it does not search for the complete call +graph. diff --git a/usr.bin/gprof/PSD.doc/refs.me b/usr.bin/gprof/PSD.doc/refs.me new file mode 100644 index 0000000..580d080 --- /dev/null +++ b/usr.bin/gprof/PSD.doc/refs.me @@ -0,0 +1,63 @@ +.\" Copyright (c) 1982, 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. +.\" +.\" @(#)refs.me 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "References" +.ls 1 +.ip [Bentley81] +Bentley, J. L., +``Writing Efficient Code'', +Department of Computer Science, +Carnegie-Mellon University, +Pittsburgh, Pennsylvania, +CMU-CS-81-116, 1981. +.ip [Graham82] +Graham, S. L., Henry, R. R., Schulman, R. A., +``An Experiment in Table Driven Code Generation'', +SIGPLAN '82 Symposium on Compiler Construction, +June, 1982. +.ip [Joy79] +Joy, W. N., Graham, S. L., Haley, C. B. ``Berkeley Pascal User's Manual'', +Version 1.1, Computer Science Division +University of California, Berkeley, CA. April 1979. +.ip [Knuth71] +Knuth, D. E. ``An empirical study of FORTRAN programs'', +Software - Practice and Experience, 1, 105-133. 1971 +.ip [Satterthwaite72] +Satterthwaite, E. ``Debugging Tools for High Level Languages'', +Software - Practice and Experience, 2, 197-217, 1972 +.ip [Tarjan72] +Tarjan, R. E., ``Depth first search and linear graph algorithm,'' +\fISIAM J. Computing\fP \fB1\fP:2, 146-160, 1972. +.ip [Unix] +Unix Programmer's Manual, ``\fBprof\fR command'', section 1, +Bell Laboratories, Murray Hill, NJ. January 1979. diff --git a/usr.bin/gprof/arcs.c b/usr.bin/gprof/arcs.c new file mode 100644 index 0000000..e5bbc24 --- /dev/null +++ b/usr.bin/gprof/arcs.c @@ -0,0 +1,950 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)arcs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + +#ifdef DEBUG +int visited; +int viable; +int newcycle; +int oldcycle; +#endif DEBUG + + /* + * add (or just increment) an arc + */ +addarc( parentp , childp , count ) + nltype *parentp; + nltype *childp; + long count; +{ + arctype *arcp; + +# ifdef DEBUG + if ( debug & TALLYDEBUG ) { + printf( "[addarc] %d arcs from %s to %s\n" , + count , parentp -> name , childp -> name ); + } +# endif DEBUG + arcp = arclookup( parentp , childp ); + if ( arcp != 0 ) { + /* + * a hit: just increment the count. + */ +# ifdef DEBUG + if ( debug & TALLYDEBUG ) { + printf( "[tally] hit %d += %d\n" , + arcp -> arc_count , count ); + } +# endif DEBUG + arcp -> arc_count += count; + return; + } + arcp = (arctype *)calloc( 1 , sizeof *arcp ); + arcp -> arc_parentp = parentp; + arcp -> arc_childp = childp; + arcp -> arc_count = count; + /* + * prepend this child to the children of this parent + */ + arcp -> arc_childlist = parentp -> children; + parentp -> children = arcp; + /* + * prepend this parent to the parents of this child + */ + arcp -> arc_parentlist = childp -> parents; + childp -> parents = arcp; +} + + /* + * the code below topologically sorts the graph (collapsing cycles), + * and propagates time bottom up and flags top down. + */ + + /* + * the topologically sorted name list pointers + */ +nltype **topsortnlp; + +topcmp( npp1 , npp2 ) + nltype **npp1; + nltype **npp2; +{ + return (*npp1) -> toporder - (*npp2) -> toporder; +} + +nltype ** +doarcs() +{ + nltype *parentp, **timesortnlp; + arctype *arcp; + long index; + long pass; + + /* + * initialize various things: + * zero out child times. + * count self-recursive calls. + * indicate that nothing is on cycles. + */ + for ( parentp = nl ; parentp < npe ; parentp++ ) { + parentp -> childtime = 0.0; + arcp = arclookup( parentp , parentp ); + if ( arcp != 0 ) { + parentp -> ncall -= arcp -> arc_count; + parentp -> selfcalls = arcp -> arc_count; + } else { + parentp -> selfcalls = 0; + } + parentp -> npropcall = parentp -> ncall; + parentp -> propfraction = 0.0; + parentp -> propself = 0.0; + parentp -> propchild = 0.0; + parentp -> printflag = FALSE; + parentp -> toporder = DFN_NAN; + parentp -> cycleno = 0; + parentp -> cyclehead = parentp; + parentp -> cnext = 0; + if ( cflag ) { + findcall( parentp , parentp -> value , (parentp+1) -> value ); + } + } + for ( pass = 1 ; ; pass++ ) { + /* + * topologically order things + * if any node is unnumbered, + * number it and any of its descendents. + */ + for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) { + if ( parentp -> toporder == DFN_NAN ) { + dfn( parentp ); + } + } + /* + * link together nodes on the same cycle + */ + cyclelink(); + /* + * if no cycles to break up, proceed + */ + if ( ! Cflag ) + break; + /* + * analyze cycles to determine breakup + */ +# ifdef DEBUG + if ( debug & BREAKCYCLE ) { + printf("[doarcs] pass %d, cycle(s) %d\n" , pass , ncycle ); + } +# endif DEBUG + if ( pass == 1 ) { + printf( "\n\n%s %s\n%s %d:\n" , + "The following arcs were deleted" , + "from the propagation calculation" , + "to reduce the maximum cycle size to", cyclethreshold ); + } + if ( cycleanalyze() ) + break; + free ( cyclenl ); + ncycle = 0; + for ( parentp = nl ; parentp < npe ; parentp++ ) { + parentp -> toporder = DFN_NAN; + parentp -> cycleno = 0; + parentp -> cyclehead = parentp; + parentp -> cnext = 0; + } + } + if ( pass > 1 ) { + printf( "\f\n" ); + } else { + printf( "\tNone\n\n" ); + } + /* + * Sort the symbol table in reverse topological order + */ + topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) ); + if ( topsortnlp == (nltype **) 0 ) { + fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" ); + } + for ( index = 0 ; index < nname ; index += 1 ) { + topsortnlp[ index ] = &nl[ index ]; + } + qsort( topsortnlp , nname , sizeof(nltype *) , topcmp ); +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[doarcs] topological sort listing\n" ); + for ( index = 0 ; index < nname ; index += 1 ) { + printf( "[doarcs] " ); + printf( "%d:" , topsortnlp[ index ] -> toporder ); + printname( topsortnlp[ index ] ); + printf( "\n" ); + } + } +# endif DEBUG + /* + * starting from the topological top, + * propagate print flags to children. + * also, calculate propagation fractions. + * this happens before time propagation + * since time propagation uses the fractions. + */ + doflags(); + /* + * starting from the topological bottom, + * propogate children times up to parents. + */ + dotime(); + /* + * Now, sort by propself + propchild. + * sorting both the regular function names + * and cycle headers. + */ + timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); + if ( timesortnlp == (nltype **) 0 ) { + fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); + } + for ( index = 0 ; index < nname ; index++ ) { + timesortnlp[index] = &nl[index]; + } + for ( index = 1 ; index <= ncycle ; index++ ) { + timesortnlp[nname+index-1] = &cyclenl[index]; + } + qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp ); + for ( index = 0 ; index < nname + ncycle ; index++ ) { + timesortnlp[ index ] -> index = index + 1; + } + return( timesortnlp ); +} + +dotime() +{ + int index; + + cycletime(); + for ( index = 0 ; index < nname ; index += 1 ) { + timepropagate( topsortnlp[ index ] ); + } +} + +timepropagate( parentp ) + nltype *parentp; +{ + arctype *arcp; + nltype *childp; + double share; + double propshare; + + if ( parentp -> propfraction == 0.0 ) { + return; + } + /* + * gather time from children of this parent. + */ + for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { + childp = arcp -> arc_childp; + if ( arcp -> arc_flags & DEADARC ) { + continue; + } + if ( arcp -> arc_count == 0 ) { + continue; + } + if ( childp == parentp ) { + continue; + } + if ( childp -> propfraction == 0.0 ) { + continue; + } + if ( childp -> cyclehead != childp ) { + if ( parentp -> cycleno == childp -> cycleno ) { + continue; + } + if ( parentp -> toporder <= childp -> toporder ) { + fprintf( stderr , "[propagate] toporder botches\n" ); + } + childp = childp -> cyclehead; + } else { + if ( parentp -> toporder <= childp -> toporder ) { + fprintf( stderr , "[propagate] toporder botches\n" ); + continue; + } + } + if ( childp -> npropcall == 0 ) { + continue; + } + /* + * distribute time for this arc + */ + arcp -> arc_time = childp -> time + * ( ( (double) arcp -> arc_count ) / + ( (double) childp -> npropcall ) ); + arcp -> arc_childtime = childp -> childtime + * ( ( (double) arcp -> arc_count ) / + ( (double) childp -> npropcall ) ); + share = arcp -> arc_time + arcp -> arc_childtime; + parentp -> childtime += share; + /* + * ( 1 - propfraction ) gets lost along the way + */ + propshare = parentp -> propfraction * share; + /* + * fix things for printing + */ + parentp -> propchild += propshare; + arcp -> arc_time *= parentp -> propfraction; + arcp -> arc_childtime *= parentp -> propfraction; + /* + * add this share to the parent's cycle header, if any. + */ + if ( parentp -> cyclehead != parentp ) { + parentp -> cyclehead -> childtime += share; + parentp -> cyclehead -> propchild += propshare; + } +# ifdef DEBUG + if ( debug & PROPDEBUG ) { + printf( "[dotime] child \t" ); + printname( childp ); + printf( " with %f %f %d/%d\n" , + childp -> time , childp -> childtime , + arcp -> arc_count , childp -> npropcall ); + printf( "[dotime] parent\t" ); + printname( parentp ); + printf( "\n[dotime] share %f\n" , share ); + } +# endif DEBUG + } +} + +cyclelink() +{ + register nltype *nlp; + register nltype *cyclenlp; + int cycle; + nltype *memberp; + arctype *arcp; + + /* + * Count the number of cycles, and initialze the cycle lists + */ + ncycle = 0; + for ( nlp = nl ; nlp < npe ; nlp++ ) { + /* + * this is how you find unattached cycles + */ + if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) { + ncycle += 1; + } + } + /* + * cyclenl is indexed by cycle number: + * i.e. it is origin 1, not origin 0. + */ + cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) ); + if ( cyclenl == 0 ) { + fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" , + whoami , ( ncycle + 1 ) * sizeof( nltype ) ); + done(); + } + /* + * now link cycles to true cycleheads, + * number them, accumulate the data for the cycle + */ + cycle = 0; + for ( nlp = nl ; nlp < npe ; nlp++ ) { + if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) { + continue; + } + cycle += 1; + cyclenlp = &cyclenl[cycle]; + cyclenlp -> name = 0; /* the name */ + cyclenlp -> value = 0; /* the pc entry point */ + cyclenlp -> time = 0.0; /* ticks in this routine */ + cyclenlp -> childtime = 0.0; /* cumulative ticks in children */ + cyclenlp -> ncall = 0; /* how many times called */ + cyclenlp -> selfcalls = 0; /* how many calls to self */ + cyclenlp -> propfraction = 0.0; /* what % of time propagates */ + cyclenlp -> propself = 0.0; /* how much self time propagates */ + cyclenlp -> propchild = 0.0; /* how much child time propagates */ + cyclenlp -> printflag = TRUE; /* should this be printed? */ + cyclenlp -> index = 0; /* index in the graph list */ + cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */ + cyclenlp -> cycleno = cycle; /* internal number of cycle on */ + cyclenlp -> cyclehead = cyclenlp; /* pointer to head of cycle */ + cyclenlp -> cnext = nlp; /* pointer to next member of cycle */ + cyclenlp -> parents = 0; /* list of caller arcs */ + cyclenlp -> children = 0; /* list of callee arcs */ +# ifdef DEBUG + if ( debug & CYCLEDEBUG ) { + printf( "[cyclelink] " ); + printname( nlp ); + printf( " is the head of cycle %d\n" , cycle ); + } +# endif DEBUG + /* + * link members to cycle header + */ + for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { + memberp -> cycleno = cycle; + memberp -> cyclehead = cyclenlp; + } + /* + * count calls from outside the cycle + * and those among cycle members + */ + for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { + for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) { + if ( arcp -> arc_parentp == memberp ) { + continue; + } + if ( arcp -> arc_parentp -> cycleno == cycle ) { + cyclenlp -> selfcalls += arcp -> arc_count; + } else { + cyclenlp -> npropcall += arcp -> arc_count; + } + } + } + } +} + + /* + * analyze cycles to determine breakup + */ +cycleanalyze() +{ + arctype **cyclestack; + arctype **stkp; + arctype **arcpp; + arctype **endlist; + arctype *arcp; + nltype *nlp; + cltype *clp; + bool ret; + bool done; + int size; + int cycleno; + + /* + * calculate the size of the cycle, and find nodes that + * exit the cycle as they are desirable targets to cut + * some of their parents + */ + for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) { + size = 0; + for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) { + size += 1; + nlp -> parentcnt = 0; + nlp -> flags &= ~HASCYCLEXIT; + for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) { + nlp -> parentcnt += 1; + if ( arcp -> arc_parentp -> cycleno != cycleno ) + nlp -> flags |= HASCYCLEXIT; + } + } + if ( size <= cyclethreshold ) + continue; + done = FALSE; + cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) ); + if ( cyclestack == 0 ) { + fprintf( stderr , "%s: No room for %d bytes of cycle stack\n" , + whoami , ( size + 1 ) * sizeof( arctype * ) ); + return; + } +# ifdef DEBUG + if ( debug & BREAKCYCLE ) { + printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" , + cycleno , ncycle , size ); + } +# endif DEBUG + for ( nlp = cyclenl[ cycleno ] . cnext ; nlp ; nlp = nlp -> cnext ) { + stkp = &cyclestack[0]; + nlp -> flags |= CYCLEHEAD; + ret = descend ( nlp , cyclestack , stkp ); + nlp -> flags &= ~CYCLEHEAD; + if ( ret == FALSE ) + break; + } + free( cyclestack ); + if ( cyclecnt > 0 ) { + compresslist(); + for ( clp = cyclehead ; clp ; ) { + endlist = &clp -> list[ clp -> size ]; + for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) + (*arcpp) -> arc_cyclecnt--; + cyclecnt--; + clp = clp -> next; + free( clp ); + } + cyclehead = 0; + } + } +# ifdef DEBUG + if ( debug & BREAKCYCLE ) { + printf("%s visited %d, viable %d, newcycle %d, oldcycle %d\n", + "[doarcs]" , visited , viable , newcycle , oldcycle); + } +# endif DEBUG + return( done ); +} + +descend( node , stkstart , stkp ) + nltype *node; + arctype **stkstart; + arctype **stkp; +{ + arctype *arcp; + bool ret; + + for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) { +# ifdef DEBUG + visited++; +# endif DEBUG + if ( arcp -> arc_childp -> cycleno != node -> cycleno + || ( arcp -> arc_childp -> flags & VISITED ) + || ( arcp -> arc_flags & DEADARC ) ) + continue; +# ifdef DEBUG + viable++; +# endif DEBUG + *stkp = arcp; + if ( arcp -> arc_childp -> flags & CYCLEHEAD ) { + if ( addcycle( stkstart , stkp ) == FALSE ) + return( FALSE ); + continue; + } + arcp -> arc_childp -> flags |= VISITED; + ret = descend( arcp -> arc_childp , stkstart , stkp + 1 ); + arcp -> arc_childp -> flags &= ~VISITED; + if ( ret == FALSE ) + return( FALSE ); + } +} + +addcycle( stkstart , stkend ) + arctype **stkstart; + arctype **stkend; +{ + arctype **arcpp; + arctype **stkloc; + arctype **stkp; + arctype **endlist; + arctype *minarc; + arctype *arcp; + cltype *clp; + int size; + + size = stkend - stkstart + 1; + if ( size <= 1 ) + return( TRUE ); + for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) { + if ( *arcpp > minarc ) + continue; + minarc = *arcpp; + stkloc = arcpp; + } + for ( clp = cyclehead ; clp ; clp = clp -> next ) { + if ( clp -> size != size ) + continue; + stkp = stkloc; + endlist = &clp -> list[ size ]; + for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) { + if ( *stkp++ != *arcpp ) + break; + if ( stkp > stkend ) + stkp = stkstart; + } + if ( arcpp == endlist ) { +# ifdef DEBUG + oldcycle++; +# endif DEBUG + return( TRUE ); + } + } + clp = (cltype *) + calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) ); + if ( clp == 0 ) { + fprintf( stderr , "%s: No room for %d bytes of subcycle storage\n" , + whoami , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) ); + return( FALSE ); + } + stkp = stkloc; + endlist = &clp -> list[ size ]; + for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) { + arcp = *arcpp = *stkp++; + if ( stkp > stkend ) + stkp = stkstart; + arcp -> arc_cyclecnt++; + if ( ( arcp -> arc_flags & ONLIST ) == 0 ) { + arcp -> arc_flags |= ONLIST; + arcp -> arc_next = archead; + archead = arcp; + } + } + clp -> size = size; + clp -> next = cyclehead; + cyclehead = clp; +# ifdef DEBUG + newcycle++; + if ( debug & SUBCYCLELIST ) { + printsubcycle( clp ); + } +# endif DEBUG + cyclecnt++; + if ( cyclecnt >= CYCLEMAX ) + return( FALSE ); + return( TRUE ); +} + +compresslist() +{ + cltype *clp; + cltype **prev; + arctype **arcpp; + arctype **endlist; + arctype *arcp; + arctype *maxarcp; + arctype *maxexitarcp; + arctype *maxwithparentarcp; + arctype *maxnoparentarcp; + int maxexitcnt; + int maxwithparentcnt; + int maxnoparentcnt; + char *type; + + maxexitcnt = 0; + maxwithparentcnt = 0; + maxnoparentcnt = 0; + for ( endlist = &archead , arcp = archead ; arcp ; ) { + if ( arcp -> arc_cyclecnt == 0 ) { + arcp -> arc_flags &= ~ONLIST; + *endlist = arcp -> arc_next; + arcp -> arc_next = 0; + arcp = *endlist; + continue; + } + if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) { + if ( arcp -> arc_cyclecnt > maxexitcnt || + ( arcp -> arc_cyclecnt == maxexitcnt && + arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) { + maxexitcnt = arcp -> arc_cyclecnt; + maxexitarcp = arcp; + } + } else if ( arcp -> arc_childp -> parentcnt > 1 ) { + if ( arcp -> arc_cyclecnt > maxwithparentcnt || + ( arcp -> arc_cyclecnt == maxwithparentcnt && + arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) { + maxwithparentcnt = arcp -> arc_cyclecnt; + maxwithparentarcp = arcp; + } + } else { + if ( arcp -> arc_cyclecnt > maxnoparentcnt || + ( arcp -> arc_cyclecnt == maxnoparentcnt && + arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) { + maxnoparentcnt = arcp -> arc_cyclecnt; + maxnoparentarcp = arcp; + } + } + endlist = &arcp -> arc_next; + arcp = arcp -> arc_next; + } + if ( maxexitcnt > 0 ) { + /* + * first choice is edge leading to node with out-of-cycle parent + */ + maxarcp = maxexitarcp; +# ifdef DEBUG + type = "exit"; +# endif DEBUG + } else if ( maxwithparentcnt > 0 ) { + /* + * second choice is edge leading to node with at least one + * other in-cycle parent + */ + maxarcp = maxwithparentarcp; +# ifdef DEBUG + type = "internal"; +# endif DEBUG + } else { + /* + * last choice is edge leading to node with only this arc as + * a parent (as it will now be orphaned) + */ + maxarcp = maxnoparentarcp; +# ifdef DEBUG + type = "orphan"; +# endif DEBUG + } + maxarcp -> arc_flags |= DEADARC; + maxarcp -> arc_childp -> parentcnt -= 1; + maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count; +# ifdef DEBUG + if ( debug & BREAKCYCLE ) { + printf( "%s delete %s arc: %s (%d) -> %s from %d cycle(s)\n" , + "[compresslist]" , type , maxarcp -> arc_parentp -> name , + maxarcp -> arc_count , maxarcp -> arc_childp -> name , + maxarcp -> arc_cyclecnt ); + } +# endif DEBUG + printf( "\t%s to %s with %d calls\n" , maxarcp -> arc_parentp -> name , + maxarcp -> arc_childp -> name , maxarcp -> arc_count ); + prev = &cyclehead; + for ( clp = cyclehead ; clp ; ) { + endlist = &clp -> list[ clp -> size ]; + for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) + if ( (*arcpp) -> arc_flags & DEADARC ) + break; + if ( arcpp == endlist ) { + prev = &clp -> next; + clp = clp -> next; + continue; + } + for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) + (*arcpp) -> arc_cyclecnt--; + cyclecnt--; + *prev = clp -> next; + clp = clp -> next; + free( clp ); + } +} + +#ifdef DEBUG +printsubcycle( clp ) + cltype *clp; +{ + arctype **arcpp; + arctype **endlist; + + arcpp = clp -> list; + printf( "%s \n" , (*arcpp) -> arc_parentp -> name , + (*arcpp) -> arc_parentp -> cycleno ) ; + for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ ) + printf( "\t(%d) -> %s\n" , (*arcpp) -> arc_count , + (*arcpp) -> arc_childp -> name ) ; +} +#endif DEBUG + +cycletime() +{ + int cycle; + nltype *cyclenlp; + nltype *childp; + + for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) { + cyclenlp = &cyclenl[ cycle ]; + for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) { + if ( childp -> propfraction == 0.0 ) { + /* + * all members have the same propfraction except those + * that were excluded with -E + */ + continue; + } + cyclenlp -> time += childp -> time; + } + cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time; + } +} + + /* + * in one top to bottom pass over the topologically sorted namelist + * propagate: + * printflag as the union of parents' printflags + * propfraction as the sum of fractional parents' propfractions + * and while we're here, sum time for functions. + */ +doflags() +{ + int index; + nltype *childp; + nltype *oldhead; + + oldhead = 0; + for ( index = nname-1 ; index >= 0 ; index -= 1 ) { + childp = topsortnlp[ index ]; + /* + * if we haven't done this function or cycle, + * inherit things from parent. + * this way, we are linear in the number of arcs + * since we do all members of a cycle (and the cycle itself) + * as we hit the first member of the cycle. + */ + if ( childp -> cyclehead != oldhead ) { + oldhead = childp -> cyclehead; + inheritflags( childp ); + } +# ifdef DEBUG + if ( debug & PROPDEBUG ) { + printf( "[doflags] " ); + printname( childp ); + printf( " inherits printflag %d and propfraction %f\n" , + childp -> printflag , childp -> propfraction ); + } +# endif DEBUG + if ( ! childp -> printflag ) { + /* + * printflag is off + * it gets turned on by + * being on -f list, + * or there not being any -f list and not being on -e list. + */ + if ( onlist( flist , childp -> name ) + || ( !fflag && !onlist( elist , childp -> name ) ) ) { + childp -> printflag = TRUE; + } + } else { + /* + * this function has printing parents: + * maybe someone wants to shut it up + * by putting it on -e list. (but favor -f over -e) + */ + if ( ( !onlist( flist , childp -> name ) ) + && onlist( elist , childp -> name ) ) { + childp -> printflag = FALSE; + } + } + if ( childp -> propfraction == 0.0 ) { + /* + * no parents to pass time to. + * collect time from children if + * its on -F list, + * or there isn't any -F list and its not on -E list. + */ + if ( onlist( Flist , childp -> name ) + || ( !Fflag && !onlist( Elist , childp -> name ) ) ) { + childp -> propfraction = 1.0; + } + } else { + /* + * it has parents to pass time to, + * but maybe someone wants to shut it up + * by puttting it on -E list. (but favor -F over -E) + */ + if ( !onlist( Flist , childp -> name ) + && onlist( Elist , childp -> name ) ) { + childp -> propfraction = 0.0; + } + } + childp -> propself = childp -> time * childp -> propfraction; + printtime += childp -> propself; +# ifdef DEBUG + if ( debug & PROPDEBUG ) { + printf( "[doflags] " ); + printname( childp ); + printf( " ends up with printflag %d and propfraction %f\n" , + childp -> printflag , childp -> propfraction ); + printf( "time %f propself %f printtime %f\n" , + childp -> time , childp -> propself , printtime ); + } +# endif DEBUG + } +} + + /* + * check if any parent of this child + * (or outside parents of this cycle) + * have their print flags on and set the + * print flag of the child (cycle) appropriately. + * similarly, deal with propagation fractions from parents. + */ +inheritflags( childp ) + nltype *childp; +{ + nltype *headp; + arctype *arcp; + nltype *parentp; + nltype *memp; + + headp = childp -> cyclehead; + if ( childp == headp ) { + /* + * just a regular child, check its parents + */ + childp -> printflag = FALSE; + childp -> propfraction = 0.0; + for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) { + parentp = arcp -> arc_parentp; + if ( childp == parentp ) { + continue; + } + childp -> printflag |= parentp -> printflag; + /* + * if the child was never actually called + * (e.g. this arc is static (and all others are, too)) + * no time propagates along this arc. + */ + if ( arcp -> arc_flags & DEADARC ) { + continue; + } + if ( childp -> npropcall ) { + childp -> propfraction += parentp -> propfraction + * ( ( (double) arcp -> arc_count ) + / ( (double) childp -> npropcall ) ); + } + } + } else { + /* + * its a member of a cycle, look at all parents from + * outside the cycle + */ + headp -> printflag = FALSE; + headp -> propfraction = 0.0; + for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) { + for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) { + if ( arcp -> arc_parentp -> cyclehead == headp ) { + continue; + } + parentp = arcp -> arc_parentp; + headp -> printflag |= parentp -> printflag; + /* + * if the cycle was never actually called + * (e.g. this arc is static (and all others are, too)) + * no time propagates along this arc. + */ + if ( arcp -> arc_flags & DEADARC ) { + continue; + } + if ( headp -> npropcall ) { + headp -> propfraction += parentp -> propfraction + * ( ( (double) arcp -> arc_count ) + / ( (double) headp -> npropcall ) ); + } + } + } + for ( memp = headp ; memp ; memp = memp -> cnext ) { + memp -> printflag = headp -> printflag; + memp -> propfraction = headp -> propfraction; + } + } +} diff --git a/usr.bin/gprof/dfn.c b/usr.bin/gprof/dfn.c new file mode 100644 index 0000000..987929f --- /dev/null +++ b/usr.bin/gprof/dfn.c @@ -0,0 +1,325 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)dfn.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include "gprof.h" + +#define DFN_DEPTH 100 +struct dfnstruct { + nltype *nlentryp; + int cycletop; +}; +typedef struct dfnstruct dfntype; + +dfntype dfn_stack[ DFN_DEPTH ]; +int dfn_depth; + +int dfn_counter; + +dfn_init() +{ + + dfn_depth = 0; + dfn_counter = DFN_NAN; +} + + /* + * given this parent, depth first number its children. + */ +dfn( parentp ) + nltype *parentp; +{ + arctype *arcp; + +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn] dfn(" ); + printname( parentp ); + printf( ")\n" ); + } +# endif DEBUG + /* + * if we're already numbered, no need to look any furthur. + */ + if ( dfn_numbered( parentp ) ) { + return; + } + /* + * if we're already busy, must be a cycle + */ + if ( dfn_busy( parentp ) ) { + dfn_findcycle( parentp ); + return; + } + /* + * visit yourself before your children + */ + dfn_pre_visit( parentp ); + /* + * visit children + */ + for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { + if ( arcp -> arc_flags & DEADARC ) + continue; + dfn( arcp -> arc_childp ); + } + /* + * visit yourself after your children + */ + dfn_post_visit( parentp ); +} + + /* + * push a parent onto the stack and mark it busy + */ +dfn_pre_visit( parentp ) + nltype *parentp; +{ + + dfn_depth += 1; + if ( dfn_depth >= DFN_DEPTH ) { + fprintf( stderr , "[dfn] out of my depth (dfn_stack overflow)\n" ); + exit( 1 ); + } + dfn_stack[ dfn_depth ].nlentryp = parentp; + dfn_stack[ dfn_depth ].cycletop = dfn_depth; + parentp -> toporder = DFN_BUSY; +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_pre_visit]\t\t%d:" , dfn_depth ); + printname( parentp ); + printf( "\n" ); + } +# endif DEBUG +} + + /* + * are we already numbered? + */ +bool +dfn_numbered( childp ) + nltype *childp; +{ + + return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY ); +} + + /* + * are we already busy? + */ +bool +dfn_busy( childp ) + nltype *childp; +{ + + if ( childp -> toporder == DFN_NAN ) { + return FALSE; + } + return TRUE; +} + + /* + * MISSING: an explanation + */ +dfn_findcycle( childp ) + nltype *childp; +{ + int cycletop; + nltype *cycleheadp; + nltype *tailp; + int index; + + for ( cycletop = dfn_depth ; cycletop > 0 ; cycletop -= 1 ) { + cycleheadp = dfn_stack[ cycletop ].nlentryp; + if ( childp == cycleheadp ) { + break; + } + if ( childp -> cyclehead != childp && + childp -> cyclehead == cycleheadp ) { + break; + } + } + if ( cycletop <= 0 ) { + fprintf( stderr , "[dfn_findcycle] couldn't find head of cycle\n" ); + exit( 1 ); + } +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_findcycle] dfn_depth %d cycletop %d " , + dfn_depth , cycletop ); + printname( cycleheadp ); + printf( "\n" ); + } +# endif DEBUG + if ( cycletop == dfn_depth ) { + /* + * this is previous function, e.g. this calls itself + * sort of boring + */ + dfn_self_cycle( childp ); + } else { + /* + * glom intervening functions that aren't already + * glommed into this cycle. + * things have been glommed when their cyclehead field + * points to the head of the cycle they are glommed into. + */ + for ( tailp = cycleheadp ; tailp -> cnext ; tailp = tailp -> cnext ) { + /* void: chase down to tail of things already glommed */ +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_findcycle] tail " ); + printname( tailp ); + printf( "\n" ); + } +# endif DEBUG + } + /* + * if what we think is the top of the cycle + * has a cyclehead field, then it's not really the + * head of the cycle, which is really what we want + */ + if ( cycleheadp -> cyclehead != cycleheadp ) { + cycleheadp = cycleheadp -> cyclehead; +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_findcycle] new cyclehead " ); + printname( cycleheadp ); + printf( "\n" ); + } +# endif DEBUG + } + for ( index = cycletop + 1 ; index <= dfn_depth ; index += 1 ) { + childp = dfn_stack[ index ].nlentryp; + if ( childp -> cyclehead == childp ) { + /* + * not yet glommed anywhere, glom it + * and fix any children it has glommed + */ + tailp -> cnext = childp; + childp -> cyclehead = cycleheadp; +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_findcycle] glomming " ); + printname( childp ); + printf( " onto " ); + printname( cycleheadp ); + printf( "\n" ); + } +# endif DEBUG + for ( tailp = childp ; tailp->cnext ; tailp = tailp->cnext ) { + tailp -> cnext -> cyclehead = cycleheadp; +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_findcycle] and its tail " ); + printname( tailp -> cnext ); + printf( " onto " ); + printname( cycleheadp ); + printf( "\n" ); + } +# endif DEBUG + } + } else if ( childp -> cyclehead != cycleheadp /* firewall */ ) { + fprintf( stderr , + "[dfn_busy] glommed, but not to cyclehead\n" ); + } + } + } +} + + /* + * deal with self-cycles + * for lint: ARGSUSED + */ +dfn_self_cycle( parentp ) + nltype *parentp; +{ + /* + * since we are taking out self-cycles elsewhere + * no need for the special case, here. + */ +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_self_cycle] " ); + printname( parentp ); + printf( "\n" ); + } +# endif DEBUG +} + + /* + * visit a node after all its children + * [MISSING: an explanation] + * and pop it off the stack + */ +dfn_post_visit( parentp ) + nltype *parentp; +{ + nltype *memberp; + +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_post_visit]\t%d: " , dfn_depth ); + printname( parentp ); + printf( "\n" ); + } +# endif DEBUG + /* + * number functions and things in their cycles + * unless the function is itself part of a cycle + */ + if ( parentp -> cyclehead == parentp ) { + dfn_counter += 1; + for ( memberp = parentp ; memberp ; memberp = memberp -> cnext ) { + memberp -> toporder = dfn_counter; +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_post_visit]\t\tmember " ); + printname( memberp ); + printf( " -> toporder = %d\n" , dfn_counter ); + } +# endif DEBUG + } + } else { +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "[dfn_post_visit]\t\tis part of a cycle\n" ); + } +# endif DEBUG + } + dfn_depth -= 1; +} diff --git a/usr.bin/gprof/gprof.1 b/usr.bin/gprof/gprof.1 new file mode 100644 index 0000000..dfb0f21 --- /dev/null +++ b/usr.bin/gprof/gprof.1 @@ -0,0 +1,281 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)gprof.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt GPROF 1 +.Os BSD 4.2 +.Sh NAME +.Nm gprof +.Nd display call graph profile data +.Sh SYNOPSIS +.Nm gprof +.Op options +.Op Ar a.out Op Ar gmon.out ... +.Sh DESCRIPTION +.Nm Gprof +produces an execution profile of C, Pascal, or Fortran77 programs. +The effect of called routines is incorporated in the profile of each caller. +The profile data is taken from the call graph profile file +.Pf ( Pa gmon.out +default) which is created by programs +that are compiled with the +.Fl pg +option of +.Xr cc 1 , +.Xr pc 1 , +and +.Xr f77 1 . +The +.Fl pg +option also links in versions of the library routines +that are compiled for profiling. +.Nm Gprof +reads the given object file (the default is +.Pa a.out) +and establishes the relation between it's symbol table +and the call graph profile from +.Pa gmon.out . +If more than one profile file is specified, +the +.Nm gprof +output shows the sum of the profile information in the given profile files. +.Pp +.Nm Gprof +calculates the amount of time spent in each routine. +Next, these times are propagated along the edges of the call graph. +Cycles are discovered, and calls into a cycle are made to share the time +of the cycle. +The first listing shows the functions +sorted according to the time they represent +including the time of their call graph descendents. +Below each function entry is shown its (direct) call graph children, +and how their times are propagated to this function. +A similar display above the function shows how this function's time and the +time of its descendents is propagated to its (direct) call graph parents. +.Pp +Cycles are also shown, with an entry for the cycle as a whole and +a listing of the members of the cycle and their contributions to the +time and call counts of the cycle. +.Pp +Second, a flat profile is given, +similar to that provided by +.Xr prof 1 . +This listing gives the total execution times, the call counts, +the time in milleseconds the call spent in the routine itself, and +the time in milleseconds the call spent in the routine itself including +its descendents. +.Pp +Finally, an index of the function names is provided. +.Pp +The following options are available: +.Bl -tag -width Fl +.It Fl a +Suppresses the printing of statically declared functions. +If this option is given, all relevant information about the static function +(e.g., time samples, calls to other functions, calls from other functions) +belongs to the function loaded just before the static function in the +.Pa a.out +file. +.It Fl b +Suppresses the printing of a description of each field in the profile. +.It Fl c +The static call graph of the program is discovered by a heuristic +that examines the text space of the object file. +Static-only parents or children are shown +with call counts of 0. +.It Fl C Ar count +Find a minimal set of arcs that can be broken to eliminate all cycles with +.Ar count +or more members. +Caution: the algorithm used to break cycles is exponential, +so using this option may cause +.Nm gprof +to run for a very long time. +.It Fl e Ar name +Suppresses the printing of the graph profile entry for routine +.Ar name +and all its descendants +(unless they have other ancestors that aren't suppressed). +More than one +.Fl e +option may be given. +Only one +.Ar name +may be given with each +.Fl e +option. +.It Fl E Ar name +Suppresses the printing of the graph profile entry for routine +.Ar name +(and its descendants) as +.Fl e , +above, and also excludes the time spent in +.Ar name +(and its descendants) from the total and percentage time computations. +(For example, +.Fl E +.Ar mcount +.Fl E +.Ar mcleanup +is the default.) +.It Fl f Ar name +Prints the graph profile entry of only the specified routine +.Ar name +and its descendants. +More than one +.Fl f +option may be given. +Only one +.Ar name +may be given with each +.Fl f +option. +.It Fl F Ar name +Prints the graph profile entry of only the routine +.Ar name +and its descendants (as +.Fl f , +above) and also uses only the times of the printed routines +in total time and percentage computations. +More than one +.Fl F +option may be given. +Only one +.Ar name +may be given with each +.Fl F +option. +The +.Fl F +option +overrides +the +.Fl E +option. +.It Fl k Ar fromname Ar toname +Will delete any arcs from routine +.Ar fromname +to routine +.Ar toname . +This can be used to break undesired cycles. +More than one +.Fl k +option may be given. +Only one pair of routine names may be given with each +.Fl k +option. +.It Fl s +A profile file +.Pa gmon.sum +is produced that represents +the sum of the profile information in all the specified profile files. +This summary profile file may be given to later +executions of gprof (probably also with a +.Fl s ) +to accumulate profile data across several runs of an +.Pa a.out +file. +.It Fl z +Displays routines that have zero usage (as shown by call counts +and accumulated time). +This is useful with the +.Fl c +option for discovering which routines were never called. +.El +.Sh FILES +.Bl -tag -width gmon.sum -compact +.It Pa a.out +The namelist and text space. +.It Pa gmon.out +Dynamic call graph and profile. +.It Pa gmon.sum +Summarized dynamic call graph and profile. +.El +.Sh SEE ALSO +.Xr monitor 3 , +.Xr profil 2 , +.Xr cc 1 , +.Xr prof 1 +.Rs +.%T "An Execution Profiler for Modular Programs" +.%A S. Graham +.%A P. Kessler +.%A M. McKusick +.%J "Software - Practice and Experience" +.%V 13 +.%P pp. 671-685 +.%D 1983 +.Re +.Rs +.%T "gprof: A Call Graph Execution Profiler" +.%A S. Graham +.%A P. Kessler +.%A M. McKusick +.%J "Proceedings of the SIGPLAN '82 Symposium on Compiler Construction, SIGPLAN Notices" +.%V 17 +.%N 6 +.%P pp. 120-126 +.%D June 1982 +.Re +.Sh HISTORY +The +.Nm gprof +profiler +appeared in +.Bx 4.2 . +.Sh BUGS +The granularity of the sampling is shown, but remains +statistical at best. +We assume that the time for each execution of a function +can be expressed by the total time for the function divided +by the number of times the function is called. +Thus the time propagated along the call graph arcs to the function's +parents is directly proportional to the number of times that +arc is traversed. +.Pp +Parents that are not themselves profiled will have the time of +their profiled children propagated to them, but they will appear +to be spontaneously invoked in the call graph listing, and will +not have their time propagated further. +Similarly, signal catchers, even though profiled, will appear +to be spontaneous (although for more obscure reasons). +Any profiled children of signal catchers should have their times +propagated properly, unless the signal catcher was invoked during +the execution of the profiling routine, in which case all is lost. +.Pp +The profiled program must call +.Xr exit 2 +or return normally for the profiling information to be saved +in the +.Pa gmon.out +file. diff --git a/usr.bin/gprof/gprof.c b/usr.bin/gprof/gprof.c new file mode 100644 index 0000000..5057e32 --- /dev/null +++ b/usr.bin/gprof/gprof.c @@ -0,0 +1,749 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + +char *whoami = "gprof"; + + /* + * things which get -E excluded by default. + */ +char *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; + +static struct gmonhdr gmonhdr; + +main(argc, argv) + int argc; + char **argv; +{ + char **sp; + nltype **timesortnlp; + + --argc; + argv++; + debug = 0; + bflag = TRUE; + while ( *argv != 0 && **argv == '-' ) { + (*argv)++; + switch ( **argv ) { + case 'a': + aflag = TRUE; + break; + case 'b': + bflag = FALSE; + break; + case 'C': + Cflag = TRUE; + cyclethreshold = atoi( *++argv ); + break; + case 'c': +#if defined(vax) || defined(tahoe) + cflag = TRUE; +#else + fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n"); + exit(1); +#endif + break; + case 'd': + dflag = TRUE; + setlinebuf(stdout); + debug |= atoi( *++argv ); + debug |= ANYDEBUG; +# ifdef DEBUG + printf("[main] debug = %d\n", debug); +# else not DEBUG + printf("%s: -d ignored\n", whoami); +# endif DEBUG + break; + case 'E': + ++argv; + addlist( Elist , *argv ); + Eflag = TRUE; + addlist( elist , *argv ); + eflag = TRUE; + break; + case 'e': + addlist( elist , *++argv ); + eflag = TRUE; + break; + case 'F': + ++argv; + addlist( Flist , *argv ); + Fflag = TRUE; + addlist( flist , *argv ); + fflag = TRUE; + break; + case 'f': + addlist( flist , *++argv ); + fflag = TRUE; + break; + case 'k': + addlist( kfromlist , *++argv ); + addlist( ktolist , *++argv ); + kflag = TRUE; + break; + case 's': + sflag = TRUE; + break; + case 'z': + zflag = TRUE; + break; + } + argv++; + } + if ( *argv != 0 ) { + a_outname = *argv; + argv++; + } else { + a_outname = A_OUTNAME; + } + if ( *argv != 0 ) { + gmonname = *argv; + argv++; + } else { + gmonname = GMONNAME; + } + /* + * turn off default functions + */ + for ( sp = &defaultEs[0] ; *sp ; sp++ ) { + Eflag = TRUE; + addlist( Elist , *sp ); + eflag = TRUE; + addlist( elist , *sp ); + } + /* + * get information about a.out file. + */ + getnfile(); + /* + * get information about mon.out file(s). + */ + do { + getpfile( gmonname ); + if ( *argv != 0 ) { + gmonname = *argv; + } + } while ( *argv++ != 0 ); + /* + * how many ticks per second? + * if we can't tell, report time in ticks. + */ + if (hz == 0) { + hz = 1; + fprintf(stderr, "time is in ticks, not seconds\n"); + } + /* + * dump out a gmon.sum file if requested + */ + if ( sflag ) { + dumpsum( GMONSUM ); + } + /* + * assign samples to procedures + */ + asgnsamples(); + /* + * assemble the dynamic profile + */ + timesortnlp = doarcs(); + /* + * print the dynamic profile + */ + printgprof( timesortnlp ); + /* + * print the flat profile + */ + printprof(); + /* + * print the index + */ + printindex(); + done(); +} + + /* + * Set up string and symbol tables from a.out. + * and optionally the text space. + * On return symbol table is sorted by value. + */ +getnfile() +{ + FILE *nfile; + int valcmp(); + + nfile = fopen( a_outname ,"r"); + if (nfile == NULL) { + perror( a_outname ); + done(); + } + fread(&xbuf, 1, sizeof(xbuf), nfile); + if (N_BADMAG(xbuf)) { + fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); + done(); + } + getstrtab(nfile); + getsymtab(nfile); + gettextspace( nfile ); + qsort(nl, nname, sizeof(nltype), valcmp); + fclose(nfile); +# ifdef DEBUG + if ( debug & AOUTDEBUG ) { + register int j; + + for (j = 0; j < nname; j++){ + printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); + } + } +# endif DEBUG +} + +getstrtab(nfile) + FILE *nfile; +{ + + fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); + if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { + fprintf(stderr, "%s: %s: no string table (old format?)\n" , + whoami , a_outname ); + done(); + } + strtab = calloc(ssiz, 1); + if (strtab == NULL) { + fprintf(stderr, "%s: %s: no room for %d bytes of string table\n", + whoami , a_outname , ssiz); + done(); + } + if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { + fprintf(stderr, "%s: %s: error reading string table\n", + whoami , a_outname ); + done(); + } +} + + /* + * Read in symbol table + */ +getsymtab(nfile) + FILE *nfile; +{ + register long i; + int askfor; + struct nlist nbuf; + + /* pass1 - count symbols */ + fseek(nfile, (long)N_SYMOFF(xbuf), 0); + nname = 0; + for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { + fread(&nbuf, sizeof(nbuf), 1, nfile); + if ( ! funcsymbol( &nbuf ) ) { + continue; + } + nname++; + } + if (nname == 0) { + fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); + done(); + } + askfor = nname + 1; + nl = (nltype *) calloc( askfor , sizeof(nltype) ); + if (nl == 0) { + fprintf(stderr, "%s: No room for %d bytes of symbol table\n", + whoami, askfor * sizeof(nltype) ); + done(); + } + + /* pass2 - read symbols */ + fseek(nfile, (long)N_SYMOFF(xbuf), 0); + npe = nl; + nname = 0; + for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { + fread(&nbuf, sizeof(nbuf), 1, nfile); + if ( ! funcsymbol( &nbuf ) ) { +# ifdef DEBUG + if ( debug & AOUTDEBUG ) { + printf( "[getsymtab] rejecting: 0x%x %s\n" , + nbuf.n_type , strtab + nbuf.n_un.n_strx ); + } +# endif DEBUG + continue; + } + npe->value = nbuf.n_value; + npe->name = strtab+nbuf.n_un.n_strx; +# ifdef DEBUG + if ( debug & AOUTDEBUG ) { + printf( "[getsymtab] %d %s 0x%08x\n" , + nname , npe -> name , npe -> value ); + } +# endif DEBUG + npe++; + nname++; + } + npe->value = -1; +} + + /* + * read in the text space of an a.out file + */ +gettextspace( nfile ) + FILE *nfile; +{ + + if ( cflag == 0 ) { + return; + } + textspace = (u_char *) malloc( xbuf.a_text ); + if ( textspace == 0 ) { + fprintf( stderr , "%s: ran out room for %d bytes of text space: " , + whoami , xbuf.a_text ); + fprintf( stderr , "can't do -c\n" ); + return; + } + (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); + if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { + fprintf( stderr , "%s: couldn't read text space: " , whoami ); + fprintf( stderr , "can't do -c\n" ); + free( textspace ); + textspace = 0; + return; + } +} + /* + * information from a gmon.out file is in two parts: + * an array of sampling hits within pc ranges, + * and the arcs. + */ +getpfile(filename) + char *filename; +{ + FILE *pfile; + FILE *openpfile(); + struct rawarc arc; + + pfile = openpfile(filename); + readsamples(pfile); + /* + * the rest of the file consists of + * a bunch of tuples. + */ + while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { +# ifdef DEBUG + if ( debug & SAMPLEDEBUG ) { + printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , + arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); + } +# endif DEBUG + /* + * add this arc + */ + tally( &arc ); + } + fclose(pfile); +} + +FILE * +openpfile(filename) + char *filename; +{ + struct gmonhdr tmp; + FILE *pfile; + int size; + int rate; + + if((pfile = fopen(filename, "r")) == NULL) { + perror(filename); + done(); + } + fread(&tmp, sizeof(struct gmonhdr), 1, pfile); + if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || + tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { + fprintf(stderr, "%s: incompatible with first gmon file\n", filename); + done(); + } + gmonhdr = tmp; + if ( gmonhdr.version == GMONVERSION ) { + rate = gmonhdr.profrate; + size = sizeof(struct gmonhdr); + } else { + fseek(pfile, sizeof(struct ophdr), SEEK_SET); + size = sizeof(struct ophdr); + gmonhdr.profrate = rate = hertz(); + gmonhdr.version = GMONVERSION; + } + if (hz == 0) { + hz = rate; + } else if (hz != rate) { + fprintf(stderr, + "%s: profile clock rate (%d) %s (%d) in first gmon file\n", + filename, rate, "incompatible with clock rate", hz); + done(); + } + s_lowpc = (unsigned long) gmonhdr.lpc; + s_highpc = (unsigned long) gmonhdr.hpc; + lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); + highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); + sampbytes = gmonhdr.ncnt - size; + nsamples = sampbytes / sizeof (UNIT); +# ifdef DEBUG + if ( debug & SAMPLEDEBUG ) { + printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", + gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); + printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , + s_lowpc , s_highpc ); + printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , + lowpc , highpc ); + printf( "[openpfile] sampbytes %d nsamples %d\n" , + sampbytes , nsamples ); + printf( "[openpfile] sample rate %d\n" , hz ); + } +# endif DEBUG + return(pfile); +} + +tally( rawp ) + struct rawarc *rawp; +{ + nltype *parentp; + nltype *childp; + + parentp = nllookup( rawp -> raw_frompc ); + childp = nllookup( rawp -> raw_selfpc ); + if ( parentp == 0 || childp == 0 ) + return; + if ( kflag + && onlist( kfromlist , parentp -> name ) + && onlist( ktolist , childp -> name ) ) { + return; + } + childp -> ncall += rawp -> raw_count; +# ifdef DEBUG + if ( debug & TALLYDEBUG ) { + printf( "[tally] arc from %s to %s traversed %d times\n" , + parentp -> name , childp -> name , rawp -> raw_count ); + } +# endif DEBUG + addarc( parentp , childp , rawp -> raw_count ); +} + +/* + * dump out the gmon.sum file + */ +dumpsum( sumfile ) + char *sumfile; +{ + register nltype *nlp; + register arctype *arcp; + struct rawarc arc; + FILE *sfile; + + if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { + perror( sumfile ); + done(); + } + /* + * dump the header; use the last header read in + */ + if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { + perror( sumfile ); + done(); + } + /* + * dump the samples + */ + if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { + perror( sumfile ); + done(); + } + /* + * dump the normalized raw arc information + */ + for ( nlp = nl ; nlp < npe ; nlp++ ) { + for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { + arc.raw_frompc = arcp -> arc_parentp -> value; + arc.raw_selfpc = arcp -> arc_childp -> value; + arc.raw_count = arcp -> arc_count; + if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { + perror( sumfile ); + done(); + } +# ifdef DEBUG + if ( debug & SAMPLEDEBUG ) { + printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , + arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); + } +# endif DEBUG + } + } + fclose( sfile ); +} + +valcmp(p1, p2) + nltype *p1, *p2; +{ + if ( p1 -> value < p2 -> value ) { + return LESSTHAN; + } + if ( p1 -> value > p2 -> value ) { + return GREATERTHAN; + } + return EQUALTO; +} + +readsamples(pfile) + FILE *pfile; +{ + register i; + UNIT sample; + + if (samples == 0) { + samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); + if (samples == 0) { + fprintf( stderr , "%s: No room for %d sample pc's\n", + whoami , sampbytes / sizeof (UNIT)); + done(); + } + } + for (i = 0; i < nsamples; i++) { + fread(&sample, sizeof (UNIT), 1, pfile); + if (feof(pfile)) + break; + samples[i] += sample; + } + if (i != nsamples) { + fprintf(stderr, + "%s: unexpected EOF after reading %d/%d samples\n", + whoami , --i , nsamples ); + done(); + } +} + +/* + * Assign samples to the procedures to which they belong. + * + * There are three cases as to where pcl and pch can be + * with respect to the routine entry addresses svalue0 and svalue1 + * as shown in the following diagram. overlap computes the + * distance between the arrows, the fraction of the sample + * that is to be credited to the routine which starts at svalue0. + * + * svalue0 svalue1 + * | | + * v v + * + * +-----------------------------------------------+ + * | | + * | ->| |<- ->| |<- ->| |<- | + * | | | | | | + * +---------+ +---------+ +---------+ + * + * ^ ^ ^ ^ ^ ^ + * | | | | | | + * pcl pch pcl pch pcl pch + * + * For the vax we assert that samples will never fall in the first + * two bytes of any routine, since that is the entry mask, + * thus we give call alignentries() to adjust the entry points if + * the entry mask falls in one bucket but the code for the routine + * doesn't start until the next bucket. In conjunction with the + * alignment of routine addresses, this should allow us to have + * only one sample for every four bytes of text space and never + * have any overlap (the two end cases, above). + */ +asgnsamples() +{ + register int j; + UNIT ccnt; + double time; + unsigned long pcl, pch; + register int i; + unsigned long overlap; + unsigned long svalue0, svalue1; + + /* read samples and assign to namelist symbols */ + scale = highpc - lowpc; + scale /= nsamples; + alignentries(); + for (i = 0, j = 1; i < nsamples; i++) { + ccnt = samples[i]; + if (ccnt == 0) + continue; + pcl = lowpc + scale * i; + pch = lowpc + scale * (i + 1); + time = ccnt; +# ifdef DEBUG + if ( debug & SAMPLEDEBUG ) { + printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , + pcl , pch , ccnt ); + } +# endif DEBUG + totime += time; + for (j = j - 1; j < nname; j++) { + svalue0 = nl[j].svalue; + svalue1 = nl[j+1].svalue; + /* + * if high end of tick is below entry address, + * go for next tick. + */ + if (pch < svalue0) + break; + /* + * if low end of tick into next routine, + * go for next routine. + */ + if (pcl >= svalue1) + continue; + overlap = min(pch, svalue1) - max(pcl, svalue0); + if (overlap > 0) { +# ifdef DEBUG + if (debug & SAMPLEDEBUG) { + printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", + nl[j].value/sizeof(UNIT), svalue0, svalue1, + nl[j].name, + overlap * time / scale, overlap); + } +# endif DEBUG + nl[j].time += overlap * time / scale; + } + } + } +# ifdef DEBUG + if (debug & SAMPLEDEBUG) { + printf("[asgnsamples] totime %f\n", totime); + } +# endif DEBUG +} + + +unsigned long +min(a, b) + unsigned long a,b; +{ + if (ab) + return(a); + return(b); +} + + /* + * calculate scaled entry point addresses (to save time in asgnsamples), + * and possibly push the scaled entry points over the entry mask, + * if it turns out that the entry point is in one bucket and the code + * for a routine is in the next bucket. + */ +alignentries() +{ + register struct nl *nlp; + unsigned long bucket_of_entry; + unsigned long bucket_of_code; + + for (nlp = nl; nlp < npe; nlp++) { + nlp -> svalue = nlp -> value / sizeof(UNIT); + bucket_of_entry = (nlp->svalue - lowpc) / scale; + bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; + if (bucket_of_entry < bucket_of_code) { +# ifdef DEBUG + if (debug & SAMPLEDEBUG) { + printf("[alignentries] pushing svalue 0x%x to 0x%x\n", + nlp->svalue, nlp->svalue + UNITS_TO_CODE); + } +# endif DEBUG + nlp->svalue += UNITS_TO_CODE; + } + } +} + +bool +funcsymbol( nlistp ) + struct nlist *nlistp; +{ + extern char *strtab; /* string table from a.out */ + extern int aflag; /* if static functions aren't desired */ + char *name, c; + + /* + * must be a text symbol, + * and static text symbols don't qualify if aflag set. + */ + if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) + || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { + return FALSE; + } + /* + * can't have any `funny' characters in name, + * where `funny' includes `.', .o file names + * and `$', pascal labels. + * need to make an exception for sparc .mul & co. + * perhaps we should just drop this code entirely... + */ + name = strtab + nlistp -> n_un.n_strx; +#ifdef sparc + if ( *name == '.' ) { + char *p = name + 1; + if ( *p == 'u' ) + p++; + if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 || + strcmp ( p, "rem" ) == 0 ) + return TRUE; + } +#endif + while ( c = *name++ ) { + if ( c == '.' || c == '$' ) { + return FALSE; + } + } + return TRUE; +} + +done() +{ + + exit(0); +} diff --git a/usr.bin/gprof/gprof.callg b/usr.bin/gprof/gprof.callg new file mode 100644 index 0000000..533c96c --- /dev/null +++ b/usr.bin/gprof/gprof.callg @@ -0,0 +1,108 @@ + + + +call graph profile: + The sum of self and descendents is the major sort + for this listing. + + function entries: + +index the index of the function in the call graph + listing, as an aid to locating it (see below). + +%time the percentage of the total time of the program + accounted for by this function and its + descendents. + +self the number of seconds spent in this function + itself. + +descendents + the number of seconds spent in the descendents of + this function on behalf of this function. + +called the number of times this function is called (other + than recursive calls). + +self the number of times this function calls itself + recursively. + +name the name of the function, with an indication of + its membership in a cycle, if any. + +index the index of the function in the call graph + listing, as an aid to locating it. + + + + parent listings: + +self* the number of seconds of this function's self time + which is due to calls from this parent. + +descendents* + the number of seconds of this function's + descendent time which is due to calls from this + parent. + +called** the number of times this function is called by + this parent. This is the numerator of the + fraction which divides up the function's time to + its parents. + +total* the number of times this function was called by + all of its parents. This is the denominator of + the propagation fraction. + +parents the name of this parent, with an indication of the + parent's membership in a cycle, if any. + +index the index of this parent in the call graph + listing, as an aid in locating it. + + + + children listings: + +self* the number of seconds of this child's self time + which is due to being called by this function. + +descendent* + the number of seconds of this child's descendent's + time which is due to being called by this + function. + +called** the number of times this child is called by this + function. This is the numerator of the + propagation fraction for this child. + +total* the number of times this child is called by all + functions. This is the denominator of the + propagation fraction. + +children the name of this child, and an indication of its + membership in a cycle, if any. + +index the index of this child in the call graph listing, + as an aid to locating it. + + + + * these fields are omitted for parents (or + children) in the same cycle as the function. If + the function (or child) is a member of a cycle, + the propagated times and propagation denominator + represent the self time and descendent time of the + cycle as a whole. + + ** static-only parents and children are indicated + by a call count of 0. + + + + cycle listings: + the cycle as a whole is listed with the same + fields as a function entry. Below it are listed + the members of the cycle, and their contributions + to the time and call counts of the cycle. + diff --git a/usr.bin/gprof/gprof.flat b/usr.bin/gprof/gprof.flat new file mode 100644 index 0000000..60999a3 --- /dev/null +++ b/usr.bin/gprof/gprof.flat @@ -0,0 +1,32 @@ + + + +flat profile: + + % the percentage of the total running time of the +time program used by this function. + +cumulative a running sum of the number of seconds accounted + seconds for by this function and those listed above it. + + self the number of seconds accounted for by this +seconds function alone. This is the major sort for this + listing. + +calls the number of times this function was invoked, if + this function is profiled, else blank. + + self the average number of milliseconds spent in this +ms/call function per call, if this function is profiled, + else blank. + + total the average number of milliseconds spent in this +ms/call function and its descendents per call, if this + function is profiled, else blank. + +name the name of the function. This is the minor sort + for this listing. The index shows the location of + the function in the gprof listing. If the index is + in parenthesis it shows where it would appear in + the gprof listing if it were to be printed. + diff --git a/usr.bin/gprof/gprof.h b/usr.bin/gprof/gprof.h new file mode 100644 index 0000000..ef1cc19 --- /dev/null +++ b/usr.bin/gprof/gprof.h @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)gprof.h 8.1 (Berkeley) 6/6/93 + */ + +#include +#include +#include + +#include +#include +#include + +#if vax +# include "vax.h" +#endif +#if sparc +# include "sparc.h" +#endif +#if tahoe +# include "tahoe.h" +#endif +#if hp300 +# include "hp300.h" +#endif +#if luna68k +# include "luna68k.h" +#endif +#if i386 +# include "i386.h" +#endif +#if mips +# include "mips.h" +#endif + + + /* + * who am i, for error messages. + */ +char *whoami; + + /* + * booleans + */ +typedef int bool; +#define FALSE 0 +#define TRUE 1 + + /* + * ticks per second + */ +long hz; + +typedef u_short UNIT; /* unit of profiling */ +char *a_outname; +#define A_OUTNAME "a.out" + +char *gmonname; +#define GMONNAME "gmon.out" +#define GMONSUM "gmon.sum" + + /* + * a constructed arc, + * with pointers to the namelist entry of the parent and the child, + * a count of how many times this arc was traversed, + * and pointers to the next parent of this child and + * the next child of this parent. + */ +struct arcstruct { + struct nl *arc_parentp; /* pointer to parent's nl entry */ + struct nl *arc_childp; /* pointer to child's nl entry */ + long arc_count; /* num calls from parent to child */ + double arc_time; /* time inherited along arc */ + double arc_childtime; /* childtime inherited along arc */ + struct arcstruct *arc_parentlist; /* parents-of-this-child list */ + struct arcstruct *arc_childlist; /* children-of-this-parent list */ + struct arcstruct *arc_next; /* list of arcs on cycle */ + unsigned short arc_cyclecnt; /* num cycles involved in */ + unsigned short arc_flags; /* see below */ +}; +typedef struct arcstruct arctype; + + /* + * arc flags + */ +#define DEADARC 0x01 /* time should not propagate across the arc */ +#define ONLIST 0x02 /* arc is on list of arcs in cycles */ + + /* + * The symbol table; + * for each external in the specified file we gather + * its address, the number of calls and compute its share of cpu time. + */ +struct nl { + char *name; /* the name */ + unsigned long value; /* the pc entry point */ + unsigned long svalue; /* entry point aligned to histograms */ + double time; /* ticks in this routine */ + double childtime; /* cumulative ticks in children */ + long ncall; /* how many times called */ + long npropcall; /* times called by live arcs */ + long selfcalls; /* how many calls to self */ + double propfraction; /* what % of time propagates */ + double propself; /* how much self time propagates */ + double propchild; /* how much child time propagates */ + short printflag; /* should this be printed? */ + short flags; /* see below */ + int index; /* index in the graph list */ + int toporder; /* graph call chain top-sort order */ + int cycleno; /* internal number of cycle on */ + int parentcnt; /* number of live parent arcs */ + struct nl *cyclehead; /* pointer to head of cycle */ + struct nl *cnext; /* pointer to next member of cycle */ + arctype *parents; /* list of caller arcs */ + arctype *children; /* list of callee arcs */ +}; +typedef struct nl nltype; + +nltype *nl; /* the whole namelist */ +nltype *npe; /* the virtual end of the namelist */ +int nname; /* the number of function names */ + +#define HASCYCLEXIT 0x08 /* node has arc exiting from cycle */ +#define CYCLEHEAD 0x10 /* node marked as head of a cycle */ +#define VISITED 0x20 /* node visited during a cycle */ + + /* + * The cycle list. + * for each subcycle within an identified cycle, we gather + * its size and the list of included arcs. + */ +struct cl { + int size; /* length of cycle */ + struct cl *next; /* next member of list */ + arctype *list[1]; /* list of arcs in cycle */ + /* actually longer */ +}; +typedef struct cl cltype; + +arctype *archead; /* the head of arcs in current cycle list */ +cltype *cyclehead; /* the head of the list */ +int cyclecnt; /* the number of cycles found */ +#define CYCLEMAX 100 /* maximum cycles before cutting one of them */ + + /* + * flag which marks a nl entry as topologically ``busy'' + * flag which marks a nl entry as topologically ``not_numbered'' + */ +#define DFN_BUSY -1 +#define DFN_NAN 0 + + /* + * namelist entries for cycle headers. + * the number of discovered cycles. + */ +nltype *cyclenl; /* cycle header namelist */ +int ncycle; /* number of cycles discovered */ + + /* + * The header on the gmon.out file. + * gmon.out consists of a struct phdr (defined in gmon.h) + * and then an array of ncnt samples representing the + * discretized program counter values. + * + * Backward compatible old style header + */ +struct ophdr { + UNIT *lpc; + UNIT *hpc; + int ncnt; +}; + +int debug; + + /* + * Each discretized pc sample has + * a count of the number of samples in its range + */ +UNIT *samples; + +unsigned long s_lowpc; /* lowpc from the profile file */ +unsigned long s_highpc; /* highpc from the profile file */ +unsigned lowpc, highpc; /* range profiled, in UNIT's */ +unsigned sampbytes; /* number of bytes of samples */ +int nsamples; /* number of samples */ +double actime; /* accumulated time thus far for putprofline */ +double totime; /* total time for all routines */ +double printtime; /* total of time being printed */ +double scale; /* scale factor converting samples to pc + values: each sample covers scale bytes */ +char *strtab; /* string table in core */ +long ssiz; /* size of the string table */ +struct exec xbuf; /* exec header of a.out */ +unsigned char *textspace; /* text space of a.out in core */ +int cyclethreshold; /* with -C, minimum cycle size to ignore */ + + /* + * option flags, from a to z. + */ +bool aflag; /* suppress static functions */ +bool bflag; /* blurbs, too */ +bool cflag; /* discovered call graph, too */ +bool Cflag; /* find cut-set to eliminate cycles */ +bool dflag; /* debugging options */ +bool eflag; /* specific functions excluded */ +bool Eflag; /* functions excluded with time */ +bool fflag; /* specific functions requested */ +bool Fflag; /* functions requested with time */ +bool kflag; /* arcs to be deleted */ +bool sflag; /* sum multiple gmon.out files */ +bool zflag; /* zero time/called functions, too */ + + /* + * structure for various string lists + */ +struct stringlist { + struct stringlist *next; + char *string; +}; +struct stringlist *elist; +struct stringlist *Elist; +struct stringlist *flist; +struct stringlist *Flist; +struct stringlist *kfromlist; +struct stringlist *ktolist; + + /* + * function declarations + */ +/* + addarc(); +*/ +int arccmp(); +arctype *arclookup(); +/* + asgnsamples(); + printblurb(); + cyclelink(); + dfn(); +*/ +bool dfn_busy(); +/* + dfn_findcycle(); +*/ +bool dfn_numbered(); +/* + dfn_post_visit(); + dfn_pre_visit(); + dfn_self_cycle(); +*/ +nltype **doarcs(); +/* + done(); + findcalls(); + flatprofheader(); + flatprofline(); +*/ +bool funcsymbol(); +/* + getnfile(); + getpfile(); + getstrtab(); + getsymtab(); + gettextspace(); + gprofheader(); + gprofline(); + main(); +*/ +unsigned long max(); +int membercmp(); +unsigned long min(); +nltype *nllookup(); +FILE *openpfile(); +long operandlength(); +operandenum operandmode(); +char *operandname(); +/* + printchildren(); + printcycle(); + printgprof(); + printmembers(); + printname(); + printparents(); + printprof(); + readsamples(); +*/ +unsigned long reladdr(); +/* + sortchildren(); + sortmembers(); + sortparents(); + tally(); + timecmp(); + topcmp(); +*/ +int totalcmp(); +/* + valcmp(); +*/ + +#define LESSTHAN -1 +#define EQUALTO 0 +#define GREATERTHAN 1 + +#define DFNDEBUG 1 +#define CYCLEDEBUG 2 +#define ARCDEBUG 4 +#define TALLYDEBUG 8 +#define TIMEDEBUG 16 +#define SAMPLEDEBUG 32 +#define AOUTDEBUG 64 +#define CALLDEBUG 128 +#define LOOKUPDEBUG 256 +#define PROPDEBUG 512 +#define BREAKCYCLE 1024 +#define SUBCYCLELIST 2048 +#define ANYDEBUG 4096 diff --git a/usr.bin/gprof/hertz.c b/usr.bin/gprof/hertz.c new file mode 100644 index 0000000..41b455f --- /dev/null +++ b/usr.bin/gprof/hertz.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)hertz.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + + /* + * discover the tick frequency of the machine + * if something goes wrong, we return 0, an impossible hertz. + */ +#define HZ_WRONG 0 + +hertz() +{ + struct itimerval tim; + + tim.it_interval.tv_sec = 0; + tim.it_interval.tv_usec = 1; + tim.it_value.tv_sec = 0; + tim.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &tim, 0); + setitimer(ITIMER_REAL, 0, &tim); + if (tim.it_interval.tv_usec < 2) + return(HZ_WRONG); + return (1000000 / tim.it_interval.tv_usec); +} diff --git a/usr.bin/gprof/hp300.c b/usr.bin/gprof/hp300.c new file mode 100644 index 0000000..6a47408 --- /dev/null +++ b/usr.bin/gprof/hp300.c @@ -0,0 +1,11 @@ +#include "gprof.h" + +/* + * gprof -c isn't currently supported... + */ +findcall( parentp , p_lowpc , p_highpc ) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ +} diff --git a/usr.bin/gprof/hp300.h b/usr.bin/gprof/hp300.h new file mode 100644 index 0000000..15b9597 --- /dev/null +++ b/usr.bin/gprof/hp300.h @@ -0,0 +1,44 @@ +/*- + * 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. + * + * @(#)hp300.h 8.1 (Berkeley) 6/6/93 + */ + + /* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 0 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + +enum opermodes { dummy }; +typedef enum opermodes operandenum; diff --git a/usr.bin/gprof/i386.c b/usr.bin/gprof/i386.c new file mode 100644 index 0000000..6a47408 --- /dev/null +++ b/usr.bin/gprof/i386.c @@ -0,0 +1,11 @@ +#include "gprof.h" + +/* + * gprof -c isn't currently supported... + */ +findcall( parentp , p_lowpc , p_highpc ) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ +} diff --git a/usr.bin/gprof/i386.h b/usr.bin/gprof/i386.h new file mode 100644 index 0000000..067e019 --- /dev/null +++ b/usr.bin/gprof/i386.h @@ -0,0 +1,44 @@ +/*- + * 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. + * + * @(#)i386.h 8.1 (Berkeley) 6/6/93 + */ + + /* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 0 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + +enum opermodes { dummy }; +typedef enum opermodes operandenum; diff --git a/usr.bin/gprof/lookup.c b/usr.bin/gprof/lookup.c new file mode 100644 index 0000000..d63c13bf --- /dev/null +++ b/usr.bin/gprof/lookup.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)lookup.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * look up an address in a sorted-by-address namelist + * this deals with misses by mapping them to the next lower + * entry point. + */ +nltype * +nllookup( address ) + unsigned long address; +{ + register long low; + register long middle; + register long high; +# ifdef DEBUG + register int probes; + + probes = 0; +# endif DEBUG + for ( low = 0 , high = nname - 1 ; low != high ; ) { +# ifdef DEBUG + probes += 1; +# endif DEBUG + middle = ( high + low ) >> 1; + if ( nl[ middle ].value <= address && nl[ middle+1 ].value > address ) { +# ifdef DEBUG + if ( debug & LOOKUPDEBUG ) { + printf( "[nllookup] %d (%d) probes\n" , probes , nname-1 ); + } +# endif DEBUG + return &nl[ middle ]; + } + if ( nl[ middle ].value > address ) { + high = middle; + } else { + low = middle + 1; + } + } +# ifdef DEBUG + if ( debug & LOOKUPDEBUG ) { + fprintf( stderr , "[nllookup] (%d) binary search fails\n" , + nname-1 ); + } +# endif DEBUG + return 0; +} + +arctype * +arclookup( parentp , childp ) + nltype *parentp; + nltype *childp; +{ + arctype *arcp; + + if ( parentp == 0 || childp == 0 ) { + fprintf( stderr, "[arclookup] parentp == 0 || childp == 0\n" ); + return 0; + } +# ifdef DEBUG + if ( debug & LOOKUPDEBUG ) { + printf( "[arclookup] parent %s child %s\n" , + parentp -> name , childp -> name ); + } +# endif DEBUG + for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { +# ifdef DEBUG + if ( debug & LOOKUPDEBUG ) { + printf( "[arclookup]\t arc_parent %s arc_child %s\n" , + arcp -> arc_parentp -> name , + arcp -> arc_childp -> name ); + } +# endif DEBUG + if ( arcp -> arc_childp == childp ) { + return arcp; + } + } + return 0; +} diff --git a/usr.bin/gprof/mips.c b/usr.bin/gprof/mips.c new file mode 100644 index 0000000..295d64e --- /dev/null +++ b/usr.bin/gprof/mips.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. Modified by Ralph Campbell for mips. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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: sparc.c 5.1 (Berkeley) 7/7/92 + */ + +#ifndef lint +static char sccsid[] = "@(#)mips.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * a namelist entry to be the child of indirect calls + */ +nltype indirectchild = { + "(*)" , /* the name */ + (unsigned long) 0 , /* the pc entry point */ + (unsigned long) 0 , /* entry point aligned to histogram */ + (double) 0.0 , /* ticks in this routine */ + (double) 0.0 , /* cumulative ticks in children */ + (long) 0 , /* how many times called */ + (long) 0 , /* times called by live arcs */ + (long) 0 , /* how many calls to self */ + (double) 1.0 , /* propagation fraction */ + (double) 0.0 , /* self propagation time */ + (double) 0.0 , /* child propagation time */ + (short) 0 , /* print flag */ + (short) 0 , /* flags */ + (int) 0 , /* index in the graph list */ + (int) 0 , /* graph call chain top-sort order */ + (int) 0 , /* internal number of cycle on */ + (int) 0 , /* number of live parent arcs */ + (struct nl *) &indirectchild , /* pointer to head of cycle */ + (struct nl *) 0 , /* pointer to next member of cycle */ + (arctype *) 0 , /* list of caller arcs */ + (arctype *) 0 /* list of callee arcs */ +}; + +findcall(parentp, p_lowpc, p_highpc) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ + register u_long pc; + nltype *childp; + unsigned long destpc; + register long op; + register int off; + + if (textspace == 0) + return; + if (p_lowpc < s_lowpc) + p_lowpc = s_lowpc; + if (p_highpc > s_highpc) + p_highpc = s_highpc; + + for (pc = p_lowpc; pc < p_highpc; pc += 4) { + off = pc - s_lowpc; + op = *(u_long *)&textspace[off]; + if ((op & 0xfc000000) == 0x0c000000) { + /* + * a jal insn -- check that this + * is the address of a function. + */ + off = (op & 0x03ffffff) << 2; + destpc = (pc & 0xf0000000) | off; + if (destpc >= s_lowpc && destpc <= s_highpc) { + childp = nllookup(destpc); + if (childp != 0 && childp->value == destpc) + addarc(parentp, childp, 0L); + } + } else if ((op & 0xfc00f83f) == 0x0000f809) + /* + * A jalr -- an indirect call. + */ + addarc(parentp, &indirectchild, 0L); + } +} diff --git a/usr.bin/gprof/mips.h b/usr.bin/gprof/mips.h new file mode 100644 index 0000000..cd67a43 --- /dev/null +++ b/usr.bin/gprof/mips.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. Modified by Ralph Campbell for mips. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mips.h 8.1 (Berkeley) 6/6/93 + * + * From: @(#)sparc.h 5.1 (Berkeley) 7/8/92 + */ + +/* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 0 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + +enum opermodes { dummy }; +typedef enum opermodes operandenum; diff --git a/usr.bin/gprof/pathnames.h b/usr.bin/gprof/pathnames.h new file mode 100644 index 0000000..ea554c6 --- /dev/null +++ b/usr.bin/gprof/pathnames.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_FLAT_BLURB "/usr/share/misc/gprof.flat" +#define _PATH_CALLG_BLURB "/usr/share/misc/gprof.callg" + diff --git a/usr.bin/gprof/printgprof.c b/usr.bin/gprof/printgprof.c new file mode 100644 index 0000000..5ede772 --- /dev/null +++ b/usr.bin/gprof/printgprof.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)printgprof.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" +#include "pathnames.h" + +printprof() +{ + register nltype *np; + nltype **sortednlp; + int index, timecmp(); + + actime = 0.0; + printf( "\f\n" ); + flatprofheader(); + /* + * Sort the symbol table in by time + */ + sortednlp = (nltype **) calloc( nname , sizeof(nltype *) ); + if ( sortednlp == (nltype **) 0 ) { + fprintf( stderr , "[printprof] ran out of memory for time sorting\n" ); + } + for ( index = 0 ; index < nname ; index += 1 ) { + sortednlp[ index ] = &nl[ index ]; + } + qsort( sortednlp , nname , sizeof(nltype *) , timecmp ); + for ( index = 0 ; index < nname ; index += 1 ) { + np = sortednlp[ index ]; + flatprofline( np ); + } + actime = 0.0; + free( sortednlp ); +} + +timecmp( npp1 , npp2 ) + nltype **npp1, **npp2; +{ + double timediff; + long calldiff; + + timediff = (*npp2) -> time - (*npp1) -> time; + if ( timediff > 0.0 ) + return 1 ; + if ( timediff < 0.0 ) + return -1; + calldiff = (*npp2) -> ncall - (*npp1) -> ncall; + if ( calldiff > 0 ) + return 1; + if ( calldiff < 0 ) + return -1; + return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); +} + + /* + * header for flatprofline + */ +flatprofheader() +{ + + if ( bflag ) { + printblurb( _PATH_FLAT_BLURB ); + } + printf( "\ngranularity: each sample hit covers %d byte(s)" , + (long) scale * sizeof(UNIT) ); + if ( totime > 0.0 ) { + printf( " for %.2f%% of %.2f seconds\n\n" , + 100.0/totime , totime / hz ); + } else { + printf( " no time accumulated\n\n" ); + /* + * this doesn't hurt sinc eall the numerators will be zero. + */ + totime = 1.0; + } + printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , + "% " , "cumulative" , "self " , "" , "self " , "total " , "" ); + printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n" , + "time" , "seconds " , "seconds" , "calls" , + "ms/call" , "ms/call" , "name" ); +} + +flatprofline( np ) + register nltype *np; +{ + + if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) { + return; + } + actime += np -> time; + printf( "%5.1f %10.2f %8.2f" , + 100 * np -> time / totime , actime / hz , np -> time / hz ); + if ( np -> ncall != 0 ) { + printf( " %8d %8.2f %8.2f " , np -> ncall , + 1000 * np -> time / hz / np -> ncall , + 1000 * ( np -> time + np -> childtime ) / hz / np -> ncall ); + } else { + printf( " %8.8s %8.8s %8.8s " , "" , "" , "" ); + } + printname( np ); + printf( "\n" ); +} + +gprofheader() +{ + + if ( bflag ) { + printblurb( _PATH_CALLG_BLURB ); + } + printf( "\ngranularity: each sample hit covers %d byte(s)" , + (long) scale * sizeof(UNIT) ); + if ( printtime > 0.0 ) { + printf( " for %.2f%% of %.2f seconds\n\n" , + 100.0/printtime , printtime / hz ); + } else { + printf( " no time propagated\n\n" ); + /* + * this doesn't hurt, since all the numerators will be 0.0 + */ + printtime = 1.0; + } + printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , + "" , "" , "" , "" , "called" , "total" , "parents"); + printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" , + "index" , "%time" , "self" , "descendents" , + "called" , "self" , "name" , "index" ); + printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n" , + "" , "" , "" , "" , "called" , "total" , "children"); + printf( "\n" ); +} + +gprofline( np ) + register nltype *np; +{ + char kirkbuffer[ BUFSIZ ]; + + sprintf( kirkbuffer , "[%d]" , np -> index ); + printf( "%-6.6s %5.1f %7.2f %11.2f" , + kirkbuffer , + 100 * ( np -> propself + np -> propchild ) / printtime , + np -> propself / hz , + np -> propchild / hz ); + if ( ( np -> ncall + np -> selfcalls ) != 0 ) { + printf( " %7d" , np -> npropcall ); + if ( np -> selfcalls != 0 ) { + printf( "+%-7d " , np -> selfcalls ); + } else { + printf( " %7.7s " , "" ); + } + } else { + printf( " %7.7s %7.7s " , "" , "" ); + } + printname( np ); + printf( "\n" ); +} + +printgprof(timesortnlp) + nltype **timesortnlp; +{ + int index; + nltype *parentp; + + /* + * Print out the structured profiling list + */ + gprofheader(); + for ( index = 0 ; index < nname + ncycle ; index ++ ) { + parentp = timesortnlp[ index ]; + if ( zflag == 0 && + parentp -> ncall == 0 && + parentp -> selfcalls == 0 && + parentp -> propself == 0 && + parentp -> propchild == 0 ) { + continue; + } + if ( ! parentp -> printflag ) { + continue; + } + if ( parentp -> name == 0 && parentp -> cycleno != 0 ) { + /* + * cycle header + */ + printcycle( parentp ); + printmembers( parentp ); + } else { + printparents( parentp ); + gprofline( parentp ); + printchildren( parentp ); + } + printf( "\n" ); + printf( "-----------------------------------------------\n" ); + printf( "\n" ); + } + free( timesortnlp ); +} + + /* + * sort by decreasing propagated time + * if times are equal, but one is a cycle header, + * say that's first (e.g. less, i.e. -1). + * if one's name doesn't have an underscore and the other does, + * say the one is first. + * all else being equal, sort by names. + */ +int +totalcmp( npp1 , npp2 ) + nltype **npp1; + nltype **npp2; +{ + register nltype *np1 = *npp1; + register nltype *np2 = *npp2; + double diff; + + diff = ( np1 -> propself + np1 -> propchild ) + - ( np2 -> propself + np2 -> propchild ); + if ( diff < 0.0 ) + return 1; + if ( diff > 0.0 ) + return -1; + if ( np1 -> name == 0 && np1 -> cycleno != 0 ) + return -1; + if ( np2 -> name == 0 && np2 -> cycleno != 0 ) + return 1; + if ( np1 -> name == 0 ) + return -1; + if ( np2 -> name == 0 ) + return 1; + if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' ) + return -1; + if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' ) + return 1; + if ( np1 -> ncall > np2 -> ncall ) + return -1; + if ( np1 -> ncall < np2 -> ncall ) + return 1; + return strcmp( np1 -> name , np2 -> name ); +} + +printparents( childp ) + nltype *childp; +{ + nltype *parentp; + arctype *arcp; + nltype *cycleheadp; + + if ( childp -> cyclehead != 0 ) { + cycleheadp = childp -> cyclehead; + } else { + cycleheadp = childp; + } + if ( childp -> parents == 0 ) { + printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s \n" , + "" , "" , "" , "" , "" , "" ); + return; + } + sortparents( childp ); + for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) { + parentp = arcp -> arc_parentp; + if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) || + ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) { + /* + * selfcall or call among siblings + */ + printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , + "" , "" , "" , "" , + arcp -> arc_count , "" ); + printname( parentp ); + printf( "\n" ); + } else { + /* + * regular parent of child + */ + printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , + "" , "" , + arcp -> arc_time / hz , arcp -> arc_childtime / hz , + arcp -> arc_count , cycleheadp -> npropcall ); + printname( parentp ); + printf( "\n" ); + } + } +} + +printchildren( parentp ) + nltype *parentp; +{ + nltype *childp; + arctype *arcp; + + sortchildren( parentp ); + arcp = parentp -> children; + for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { + childp = arcp -> arc_childp; + if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) || + ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) { + /* + * self call or call to sibling + */ + printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s " , + "" , "" , "" , "" , arcp -> arc_count , "" ); + printname( childp ); + printf( "\n" ); + } else { + /* + * regular child of parent + */ + printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d " , + "" , "" , + arcp -> arc_time / hz , arcp -> arc_childtime / hz , + arcp -> arc_count , childp -> cyclehead -> npropcall ); + printname( childp ); + printf( "\n" ); + } + } +} + +printname( selfp ) + nltype *selfp; +{ + + if ( selfp -> name != 0 ) { + printf( "%s" , selfp -> name ); +# ifdef DEBUG + if ( debug & DFNDEBUG ) { + printf( "{%d} " , selfp -> toporder ); + } + if ( debug & PROPDEBUG ) { + printf( "%5.2f%% " , selfp -> propfraction ); + } +# endif DEBUG + } + if ( selfp -> cycleno != 0 ) { + printf( " " , selfp -> cycleno ); + } + if ( selfp -> index != 0 ) { + if ( selfp -> printflag ) { + printf( " [%d]" , selfp -> index ); + } else { + printf( " (%d)" , selfp -> index ); + } + } +} + +sortchildren( parentp ) + nltype *parentp; +{ + arctype *arcp; + arctype *detachedp; + arctype sorted; + arctype *prevp; + + /* + * unlink children from parent, + * then insertion sort back on to sorted's children. + * *arcp the arc you have detached and are inserting. + * *detachedp the rest of the arcs to be sorted. + * sorted arc list onto which you insertion sort. + * *prevp arc before the arc you are comparing. + */ + sorted.arc_childlist = 0; + for ( (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist); + arcp ; + (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) { + /* + * consider *arcp as disconnected + * insert it into sorted + */ + for ( prevp = &sorted ; + prevp -> arc_childlist ; + prevp = prevp -> arc_childlist ) { + if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) { + break; + } + } + arcp -> arc_childlist = prevp -> arc_childlist; + prevp -> arc_childlist = arcp; + } + /* + * reattach sorted children to parent + */ + parentp -> children = sorted.arc_childlist; +} + +sortparents( childp ) + nltype *childp; +{ + arctype *arcp; + arctype *detachedp; + arctype sorted; + arctype *prevp; + + /* + * unlink parents from child, + * then insertion sort back on to sorted's parents. + * *arcp the arc you have detached and are inserting. + * *detachedp the rest of the arcs to be sorted. + * sorted arc list onto which you insertion sort. + * *prevp arc before the arc you are comparing. + */ + sorted.arc_parentlist = 0; + for ( (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist); + arcp ; + (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) { + /* + * consider *arcp as disconnected + * insert it into sorted + */ + for ( prevp = &sorted ; + prevp -> arc_parentlist ; + prevp = prevp -> arc_parentlist ) { + if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) { + break; + } + } + arcp -> arc_parentlist = prevp -> arc_parentlist; + prevp -> arc_parentlist = arcp; + } + /* + * reattach sorted arcs to child + */ + childp -> parents = sorted.arc_parentlist; +} + + /* + * print a cycle header + */ +printcycle( cyclep ) + nltype *cyclep; +{ + char kirkbuffer[ BUFSIZ ]; + + sprintf( kirkbuffer , "[%d]" , cyclep -> index ); + printf( "%-6.6s %5.1f %7.2f %11.2f %7d" , + kirkbuffer , + 100 * ( cyclep -> propself + cyclep -> propchild ) / printtime , + cyclep -> propself / hz , + cyclep -> propchild / hz , + cyclep -> npropcall ); + if ( cyclep -> selfcalls != 0 ) { + printf( "+%-7d" , cyclep -> selfcalls ); + } else { + printf( " %7.7s" , "" ); + } + printf( " \t[%d]\n" , + cyclep -> cycleno , cyclep -> index ); +} + + /* + * print the members of a cycle + */ +printmembers( cyclep ) + nltype *cyclep; +{ + nltype *memberp; + + sortmembers( cyclep ); + for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) { + printf( "%6.6s %5.5s %7.2f %11.2f %7d" , + "" , "" , memberp -> propself / hz , memberp -> propchild / hz , + memberp -> npropcall ); + if ( memberp -> selfcalls != 0 ) { + printf( "+%-7d" , memberp -> selfcalls ); + } else { + printf( " %7.7s" , "" ); + } + printf( " " ); + printname( memberp ); + printf( "\n" ); + } +} + + /* + * sort members of a cycle + */ +sortmembers( cyclep ) + nltype *cyclep; +{ + nltype *todo; + nltype *doing; + nltype *prev; + + /* + * detach cycle members from cyclehead, + * and insertion sort them back on. + */ + todo = cyclep -> cnext; + cyclep -> cnext = 0; + for ( (doing = todo)&&(todo = doing -> cnext); + doing ; + (doing = todo )&&(todo = doing -> cnext )){ + for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) { + if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) { + break; + } + } + doing -> cnext = prev -> cnext; + prev -> cnext = doing; + } +} + + /* + * major sort is on propself + propchild, + * next is sort on ncalls + selfcalls. + */ +int +membercmp( this , that ) + nltype *this; + nltype *that; +{ + double thistime = this -> propself + this -> propchild; + double thattime = that -> propself + that -> propchild; + long thiscalls = this -> ncall + this -> selfcalls; + long thatcalls = that -> ncall + that -> selfcalls; + + if ( thistime > thattime ) { + return GREATERTHAN; + } + if ( thistime < thattime ) { + return LESSTHAN; + } + if ( thiscalls > thatcalls ) { + return GREATERTHAN; + } + if ( thiscalls < thatcalls ) { + return LESSTHAN; + } + return EQUALTO; +} + /* + * compare two arcs to/from the same child/parent. + * - if one arc is a self arc, it's least. + * - if one arc is within a cycle, it's less than. + * - if both arcs are within a cycle, compare arc counts. + * - if neither arc is within a cycle, compare with + * arc_time + arc_childtime as major key + * arc count as minor key + */ +int +arccmp( thisp , thatp ) + arctype *thisp; + arctype *thatp; +{ + nltype *thisparentp = thisp -> arc_parentp; + nltype *thischildp = thisp -> arc_childp; + nltype *thatparentp = thatp -> arc_parentp; + nltype *thatchildp = thatp -> arc_childp; + double thistime; + double thattime; + +# ifdef DEBUG + if ( debug & TIMEDEBUG ) { + printf( "[arccmp] " ); + printname( thisparentp ); + printf( " calls " ); + printname ( thischildp ); + printf( " %f + %f %d/%d\n" , + thisp -> arc_time , thisp -> arc_childtime , + thisp -> arc_count , thischildp -> ncall ); + printf( "[arccmp] " ); + printname( thatparentp ); + printf( " calls " ); + printname( thatchildp ); + printf( " %f + %f %d/%d\n" , + thatp -> arc_time , thatp -> arc_childtime , + thatp -> arc_count , thatchildp -> ncall ); + printf( "\n" ); + } +# endif DEBUG + if ( thisparentp == thischildp ) { + /* this is a self call */ + return LESSTHAN; + } + if ( thatparentp == thatchildp ) { + /* that is a self call */ + return GREATERTHAN; + } + if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 && + thisparentp -> cycleno == thischildp -> cycleno ) { + /* this is a call within a cycle */ + if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && + thatparentp -> cycleno == thatchildp -> cycleno ) { + /* that is a call within the cycle, too */ + if ( thisp -> arc_count < thatp -> arc_count ) { + return LESSTHAN; + } + if ( thisp -> arc_count > thatp -> arc_count ) { + return GREATERTHAN; + } + return EQUALTO; + } else { + /* that isn't a call within the cycle */ + return LESSTHAN; + } + } else { + /* this isn't a call within a cycle */ + if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 && + thatparentp -> cycleno == thatchildp -> cycleno ) { + /* that is a call within a cycle */ + return GREATERTHAN; + } else { + /* neither is a call within a cycle */ + thistime = thisp -> arc_time + thisp -> arc_childtime; + thattime = thatp -> arc_time + thatp -> arc_childtime; + if ( thistime < thattime ) + return LESSTHAN; + if ( thistime > thattime ) + return GREATERTHAN; + if ( thisp -> arc_count < thatp -> arc_count ) + return LESSTHAN; + if ( thisp -> arc_count > thatp -> arc_count ) + return GREATERTHAN; + return EQUALTO; + } + } +} + +printblurb( blurbname ) + char *blurbname; +{ + FILE *blurbfile; + int input; + + blurbfile = fopen( blurbname , "r" ); + if ( blurbfile == NULL ) { + perror( blurbname ); + return; + } + while ( ( input = getc( blurbfile ) ) != EOF ) { + putchar( input ); + } + fclose( blurbfile ); +} + +int +namecmp( npp1 , npp2 ) + nltype **npp1, **npp2; +{ + return( strcmp( (*npp1) -> name , (*npp2) -> name ) ); +} + +printindex() +{ + nltype **namesortnlp; + register nltype *nlp; + int index, nnames, todo, i, j; + char peterbuffer[ BUFSIZ ]; + + /* + * Now, sort regular function name alphbetically + * to create an index. + */ + namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) ); + if ( namesortnlp == (nltype **) 0 ) { + fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami ); + } + for ( index = 0 , nnames = 0 ; index < nname ; index++ ) { + if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 ) + continue; + namesortnlp[nnames++] = &nl[index]; + } + qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp ); + for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) { + namesortnlp[todo++] = &cyclenl[index]; + } + printf( "\f\nIndex by function name\n\n" ); + index = ( todo + 2 ) / 3; + for ( i = 0; i < index ; i++ ) { + for ( j = i; j < todo ; j += index ) { + nlp = namesortnlp[ j ]; + if ( nlp -> printflag ) { + sprintf( peterbuffer , "[%d]" , nlp -> index ); + } else { + sprintf( peterbuffer , "(%d)" , nlp -> index ); + } + if ( j < nnames ) { + printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name ); + } else { + printf( "%6.6s " , peterbuffer ); + sprintf( peterbuffer , "" , nlp -> cycleno ); + printf( "%-19.19s" , peterbuffer ); + } + } + printf( "\n" ); + } + free( namesortnlp ); +} diff --git a/usr.bin/gprof/printlist.c b/usr.bin/gprof/printlist.c new file mode 100644 index 0000000..f29ecc9 --- /dev/null +++ b/usr.bin/gprof/printlist.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)printlist.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * these are the lists of names: + * there is the list head and then the listname + * is a pointer to the list head + * (for ease of passing to stringlist functions). + */ +struct stringlist kfromhead = { 0 , 0 }; +struct stringlist *kfromlist = &kfromhead; +struct stringlist ktohead = { 0 , 0 }; +struct stringlist *ktolist = &ktohead; +struct stringlist fhead = { 0 , 0 }; +struct stringlist *flist = &fhead; +struct stringlist Fhead = { 0 , 0 }; +struct stringlist *Flist = &Fhead; +struct stringlist ehead = { 0 , 0 }; +struct stringlist *elist = &ehead; +struct stringlist Ehead = { 0 , 0 }; +struct stringlist *Elist = &Ehead; + +addlist( listp , funcname ) + struct stringlist *listp; + char *funcname; +{ + struct stringlist *slp; + + slp = (struct stringlist *) malloc( sizeof(struct stringlist)); + if ( slp == (struct stringlist *) 0 ) { + fprintf( stderr, "gprof: ran out room for printlist\n" ); + done(); + } + slp -> next = listp -> next; + slp -> string = funcname; + listp -> next = slp; +} + +bool +onlist( listp , funcname ) + struct stringlist *listp; + char *funcname; +{ + struct stringlist *slp; + + for ( slp = listp -> next ; slp ; slp = slp -> next ) { + if ( ! strcmp( slp -> string , funcname ) ) { + return TRUE; + } + if ( funcname[0] == '_' && ! strcmp( slp -> string , &funcname[1] ) ) { + return TRUE; + } + } + return FALSE; +} diff --git a/usr.bin/gprof/sparc.c b/usr.bin/gprof/sparc.c new file mode 100644 index 0000000..513a525 --- /dev/null +++ b/usr.bin/gprof/sparc.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)sparc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * a namelist entry to be the child of indirect calls + */ +nltype indirectchild = { + "(*)" , /* the name */ + (unsigned long) 0 , /* the pc entry point */ + (unsigned long) 0 , /* entry point aligned to histogram */ + (double) 0.0 , /* ticks in this routine */ + (double) 0.0 , /* cumulative ticks in children */ + (long) 0 , /* how many times called */ + (long) 0 , /* times called by live arcs */ + (long) 0 , /* how many calls to self */ + (double) 1.0 , /* propagation fraction */ + (double) 0.0 , /* self propagation time */ + (double) 0.0 , /* child propagation time */ + (short) 0 , /* print flag */ + (short) 0 , /* flags */ + (int) 0 , /* index in the graph list */ + (int) 0 , /* graph call chain top-sort order */ + (int) 0 , /* internal number of cycle on */ + (int) 0 , /* number of live parent arcs */ + (struct nl *) &indirectchild , /* pointer to head of cycle */ + (struct nl *) 0 , /* pointer to next member of cycle */ + (arctype *) 0 , /* list of caller arcs */ + (arctype *) 0 /* list of callee arcs */ +}; + +findcall(parentp, p_lowpc, p_highpc) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ + register u_long pc; + nltype *childp; + unsigned long destpc; + register long op; + register int off; + + if (textspace == 0) + return; + if (p_lowpc < s_lowpc) + p_lowpc = s_lowpc; + if (p_highpc > s_highpc) + p_highpc = s_highpc; + + for (pc = p_lowpc; pc < p_highpc; pc += 4) { + off = pc - s_lowpc; + op = *(u_long *)&textspace[off]; + if ((op & 0xc0000000) == 0x40000000) { + /* + * a pc relative call insn -- check that this + * is the address of a function. + */ + off = (op & 0x3fffffff) << 2; + destpc = pc + off; + if (destpc >= s_lowpc && destpc <= s_highpc) { + childp = nllookup(destpc); + if (childp != 0 && childp->value == destpc) + addarc(parentp, childp, 0L); + } + } else if ((op & 0xfff80000) == 0x9fc00000) + /* + * A jmpl with rd = 15 (%o7) -- an indirect call. + */ + addarc(parentp, &indirectchild, 0L); + } +} diff --git a/usr.bin/gprof/sparc.h b/usr.bin/gprof/sparc.h new file mode 100644 index 0000000..e2455ea --- /dev/null +++ b/usr.bin/gprof/sparc.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)sparc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 0 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + +enum opermodes { dummy }; +typedef enum opermodes operandenum; diff --git a/usr.bin/gprof/tahoe.c b/usr.bin/gprof/tahoe.c new file mode 100644 index 0000000..ac027f9 --- /dev/null +++ b/usr.bin/gprof/tahoe.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)tahoe.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * a namelist entry to be the child of indirect callf + */ +nltype indirectchild = { + "(*)" , /* the name */ + (unsigned long) 0 , /* the pc entry point */ + (unsigned long) 0 , /* entry point aligned to histogram */ + (double) 0.0 , /* ticks in this routine */ + (double) 0.0 , /* cumulative ticks in children */ + (long) 0 , /* how many times called */ + (long) 0 , /* how many calls to self */ + (double) 1.0 , /* propagation fraction */ + (double) 0.0 , /* self propagation time */ + (double) 0.0 , /* child propagation time */ + (bool) 0 , /* print flag */ + (int) 0 , /* index in the graph list */ + (int) 0 , /* graph call chain top-sort order */ + (int) 0 , /* internal number of cycle on */ + (struct nl *) &indirectchild , /* pointer to head of cycle */ + (struct nl *) 0 , /* pointer to next member of cycle */ + (arctype *) 0 , /* list of caller arcs */ + (arctype *) 0 /* list of callee arcs */ + }; + +operandenum +operandmode( modep ) + unsigned char *modep; +{ + long usesreg = ((long)*modep) & 0xf; + + switch ( ((long)*modep) >> 4 ) { + case 0: + case 1: + case 2: + case 3: + return literal; + case 4: + return indexed; + case 5: + return reg; + case 6: + return regdef; + case 7: + return autodec; + case 8: + return ( usesreg != 0xe ? autoinc : immediate ); + case 9: + return ( usesreg != PC ? autoincdef : absolute ); + case 10: + return ( usesreg != PC ? bytedisp : byterel ); + case 11: + return ( usesreg != PC ? bytedispdef : bytereldef ); + case 12: + return ( usesreg != PC ? worddisp : wordrel ); + case 13: + return ( usesreg != PC ? worddispdef : wordreldef ); + case 14: + return ( usesreg != PC ? longdisp : longrel ); + case 15: + return ( usesreg != PC ? longdispdef : longreldef ); + } + /* NOTREACHED */ +} + +char * +operandname( mode ) + operandenum mode; +{ + + switch ( mode ) { + case literal: + return "literal"; + case indexed: + return "indexed"; + case reg: + return "register"; + case regdef: + return "register deferred"; + case autodec: + return "autodecrement"; + case autoinc: + return "autoincrement"; + case autoincdef: + return "autoincrement deferred"; + case bytedisp: + return "byte displacement"; + case bytedispdef: + return "byte displacement deferred"; + case byterel: + return "byte relative"; + case bytereldef: + return "byte relative deferred"; + case worddisp: + return "word displacement"; + case worddispdef: + return "word displacement deferred"; + case wordrel: + return "word relative"; + case wordreldef: + return "word relative deferred"; + case immediate: + return "immediate"; + case absolute: + return "absolute"; + case longdisp: + return "long displacement"; + case longdispdef: + return "long displacement deferred"; + case longrel: + return "long relative"; + case longreldef: + return "long relative deferred"; + } + /* NOTREACHED */ +} + +long +operandlength( modep ) + unsigned char *modep; +{ + + switch ( operandmode( modep ) ) { + case literal: + case reg: + case regdef: + case autodec: + case autoinc: + case autoincdef: + return 1; + case bytedisp: + case bytedispdef: + case byterel: + case bytereldef: + return 2; + case worddisp: + case worddispdef: + case wordrel: + case wordreldef: + return 3; + case immediate: + case absolute: + case longdisp: + case longdispdef: + case longrel: + case longreldef: + return 5; + case indexed: + return 1+operandlength( modep + 1 ); + } + /* NOTREACHED */ +} + +unsigned long +reladdr( modep ) + char *modep; +{ + operandenum mode = operandmode( modep ); + char *cp; + short *sp; + long *lp; + int i; + long value = 0; + + cp = modep; + cp += 1; /* skip over the mode */ + switch ( mode ) { + default: + fprintf( stderr , "[reladdr] not relative address\n" ); + return (unsigned long) modep; + case byterel: + return (unsigned long) ( cp + sizeof *cp + *cp ); + case wordrel: + for (i = 0; i < sizeof *sp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (unsigned long) ( cp + sizeof *sp + value ); + case longrel: + for (i = 0; i < sizeof *lp; i++) + value = (value << 8) + (cp[i] & 0xff); + return (unsigned long) ( cp + sizeof *lp + value ); + } +} + +findcall( parentp , p_lowpc , p_highpc ) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ + unsigned char *instructp; + long length; + nltype *childp; + operandenum mode; + operandenum firstmode; + unsigned long destpc; + + if ( textspace == 0 ) { + return; + } + if ( p_lowpc < s_lowpc ) { + p_lowpc = s_lowpc; + } + if ( p_highpc > s_highpc ) { + p_highpc = s_highpc; + } +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall] %s: 0x%x to 0x%x\n" , + parentp -> name , p_lowpc , p_highpc ); + } +# endif DEBUG + for ( instructp = textspace + p_lowpc ; + instructp < textspace + p_highpc ; + instructp += length ) { + length = 1; + if ( *instructp == CALLF ) { + /* + * maybe a callf, better check it out. + * skip the count of the number of arguments. + */ +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\t0x%x:callf" , instructp - textspace ); + } +# endif DEBUG + firstmode = operandmode( instructp+length ); + switch ( firstmode ) { + case literal: + case immediate: + break; + default: + goto botched; + } + length += operandlength( instructp+length ); + mode = operandmode( instructp + length ); +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "\tfirst operand is %s", operandname( firstmode ) ); + printf( "\tsecond operand is %s\n" , operandname( mode ) ); + } +# endif DEBUG + switch ( mode ) { + case regdef: + case bytedispdef: + case worddispdef: + case longdispdef: + case bytereldef: + case wordreldef: + case longreldef: + /* + * indirect call: call through pointer + * either *d(r) as a parameter or local + * (r) as a return value + * *f as a global pointer + * [are there others that we miss?, + * e.g. arrays of pointers to functions???] + */ + addarc( parentp , &indirectchild , (long) 0 ); + length += operandlength( instructp + length ); + continue; + case byterel: + case wordrel: + case longrel: + /* + * regular pc relative addressing + * check that this is the address of + * a function. + */ + destpc = reladdr( instructp+length ) + - (unsigned long) textspace; + if ( destpc >= s_lowpc && destpc <= s_highpc ) { + childp = nllookup( destpc ); +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\tdestpc 0x%x" , destpc ); + printf( " childp->name %s" , childp -> name ); + printf( " childp->value 0x%x\n" , + childp -> value ); + } +# endif DEBUG + if ( childp -> value == destpc ) { + /* + * a hit + */ + addarc( parentp , childp , (long) 0 ); + length += operandlength( instructp + length ); + continue; + } + goto botched; + } + /* + * else: + * it looked like a callf, + * but it wasn't to anywhere. + */ + goto botched; + default: + botched: + /* + * something funny going on. + */ +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\tbut it's a botch\n" ); + } +# endif DEBUG + length = 1; + continue; + } + } + } +} diff --git a/usr.bin/gprof/tahoe.h b/usr.bin/gprof/tahoe.h new file mode 100644 index 0000000..7fd0d04 --- /dev/null +++ b/usr.bin/gprof/tahoe.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)tahoe.h 8.1 (Berkeley) 6/6/93 + */ + + /* + * opcode of the `callf' instruction + */ +#define CALLF 0xfe + + /* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 2 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + + /* + * register for pc relative addressing + */ +#define PC 0xf + +enum opermodes { + literal, indexed, reg, regdef, autodec, autoinc, autoincdef, + bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, + immediate, absolute, byterel, bytereldef, wordrel, wordreldef, + longrel, longreldef +}; +typedef enum opermodes operandenum; diff --git a/usr.bin/gprof/vax.c b/usr.bin/gprof/vax.c new file mode 100644 index 0000000..ec3232a --- /dev/null +++ b/usr.bin/gprof/vax.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)vax.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "gprof.h" + + /* + * a namelist entry to be the child of indirect calls + */ +nltype indirectchild = { + "(*)" , /* the name */ + (unsigned long) 0 , /* the pc entry point */ + (unsigned long) 0 , /* entry point aligned to histogram */ + (double) 0.0 , /* ticks in this routine */ + (double) 0.0 , /* cumulative ticks in children */ + (long) 0 , /* how many times called */ + (long) 0 , /* how many calls to self */ + (double) 1.0 , /* propagation fraction */ + (double) 0.0 , /* self propagation time */ + (double) 0.0 , /* child propagation time */ + (bool) 0 , /* print flag */ + (int) 0 , /* index in the graph list */ + (int) 0 , /* graph call chain top-sort order */ + (int) 0 , /* internal number of cycle on */ + (struct nl *) &indirectchild , /* pointer to head of cycle */ + (struct nl *) 0 , /* pointer to next member of cycle */ + (arctype *) 0 , /* list of caller arcs */ + (arctype *) 0 /* list of callee arcs */ + }; + +operandenum +operandmode( modep ) + struct modebyte *modep; +{ + long usesreg = modep -> regfield; + + switch ( modep -> modefield ) { + case 0: + case 1: + case 2: + case 3: + return literal; + case 4: + return indexed; + case 5: + return reg; + case 6: + return regdef; + case 7: + return autodec; + case 8: + return ( usesreg != PC ? autoinc : immediate ); + case 9: + return ( usesreg != PC ? autoincdef : absolute ); + case 10: + return ( usesreg != PC ? bytedisp : byterel ); + case 11: + return ( usesreg != PC ? bytedispdef : bytereldef ); + case 12: + return ( usesreg != PC ? worddisp : wordrel ); + case 13: + return ( usesreg != PC ? worddispdef : wordreldef ); + case 14: + return ( usesreg != PC ? longdisp : longrel ); + case 15: + return ( usesreg != PC ? longdispdef : longreldef ); + } + /* NOTREACHED */ +} + +char * +operandname( mode ) + operandenum mode; +{ + + switch ( mode ) { + case literal: + return "literal"; + case indexed: + return "indexed"; + case reg: + return "register"; + case regdef: + return "register deferred"; + case autodec: + return "autodecrement"; + case autoinc: + return "autoincrement"; + case autoincdef: + return "autoincrement deferred"; + case bytedisp: + return "byte displacement"; + case bytedispdef: + return "byte displacement deferred"; + case byterel: + return "byte relative"; + case bytereldef: + return "byte relative deferred"; + case worddisp: + return "word displacement"; + case worddispdef: + return "word displacement deferred"; + case wordrel: + return "word relative"; + case wordreldef: + return "word relative deferred"; + case immediate: + return "immediate"; + case absolute: + return "absolute"; + case longdisp: + return "long displacement"; + case longdispdef: + return "long displacement deferred"; + case longrel: + return "long relative"; + case longreldef: + return "long relative deferred"; + } + /* NOTREACHED */ +} + +long +operandlength( modep ) + struct modebyte *modep; +{ + + switch ( operandmode( modep ) ) { + case literal: + case reg: + case regdef: + case autodec: + case autoinc: + case autoincdef: + return 1; + case bytedisp: + case bytedispdef: + case byterel: + case bytereldef: + return 2; + case worddisp: + case worddispdef: + case wordrel: + case wordreldef: + return 3; + case immediate: + case absolute: + case longdisp: + case longdispdef: + case longrel: + case longreldef: + return 5; + case indexed: + return 1+operandlength( (struct modebyte *) ((char *) modep) + 1 ); + } + /* NOTREACHED */ +} + +unsigned long +reladdr( modep ) + struct modebyte *modep; +{ + operandenum mode = operandmode( modep ); + char *cp; + short *sp; + long *lp; + + cp = (char *) modep; + cp += 1; /* skip over the mode */ + switch ( mode ) { + default: + fprintf( stderr , "[reladdr] not relative address\n" ); + return (unsigned long) modep; + case byterel: + return (unsigned long) ( cp + sizeof *cp + *cp ); + case wordrel: + sp = (short *) cp; + return (unsigned long) ( cp + sizeof *sp + *sp ); + case longrel: + lp = (long *) cp; + return (unsigned long) ( cp + sizeof *lp + *lp ); + } +} + +findcall( parentp , p_lowpc , p_highpc ) + nltype *parentp; + unsigned long p_lowpc; + unsigned long p_highpc; +{ + unsigned char *instructp; + long length; + nltype *childp; + operandenum mode; + operandenum firstmode; + unsigned long destpc; + + if ( textspace == 0 ) { + return; + } + if ( p_lowpc < s_lowpc ) { + p_lowpc = s_lowpc; + } + if ( p_highpc > s_highpc ) { + p_highpc = s_highpc; + } +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall] %s: 0x%x to 0x%x\n" , + parentp -> name , p_lowpc , p_highpc ); + } +# endif DEBUG + for ( instructp = textspace + p_lowpc ; + instructp < textspace + p_highpc ; + instructp += length ) { + length = 1; + if ( *instructp == CALLS ) { + /* + * maybe a calls, better check it out. + * skip the count of the number of arguments. + */ +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\t0x%x:calls" , instructp - textspace ); + } +# endif DEBUG + firstmode = operandmode( (struct modebyte *) (instructp+length) ); + switch ( firstmode ) { + case literal: + case immediate: + break; + default: + goto botched; + } + length += operandlength( (struct modebyte *) (instructp+length) ); + mode = operandmode( (struct modebyte *) ( instructp + length ) ); +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "\tfirst operand is %s", operandname( firstmode ) ); + printf( "\tsecond operand is %s\n" , operandname( mode ) ); + } +# endif DEBUG + switch ( mode ) { + case regdef: + case bytedispdef: + case worddispdef: + case longdispdef: + case bytereldef: + case wordreldef: + case longreldef: + /* + * indirect call: call through pointer + * either *d(r) as a parameter or local + * (r) as a return value + * *f as a global pointer + * [are there others that we miss?, + * e.g. arrays of pointers to functions???] + */ + addarc( parentp , &indirectchild , (long) 0 ); + length += operandlength( + (struct modebyte *) ( instructp + length ) ); + continue; + case byterel: + case wordrel: + case longrel: + /* + * regular pc relative addressing + * check that this is the address of + * a function. + */ + destpc = reladdr( (struct modebyte *) (instructp+length) ) + - (unsigned long) textspace; + if ( destpc >= s_lowpc && destpc <= s_highpc ) { + childp = nllookup( destpc ); +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\tdestpc 0x%x" , destpc ); + printf( " childp->name %s" , childp -> name ); + printf( " childp->value 0x%x\n" , + childp -> value ); + } +# endif DEBUG + if ( childp -> value == destpc ) { + /* + * a hit + */ + addarc( parentp , childp , (long) 0 ); + length += operandlength( (struct modebyte *) + ( instructp + length ) ); + continue; + } + goto botched; + } + /* + * else: + * it looked like a calls, + * but it wasn't to anywhere. + */ + goto botched; + default: + botched: + /* + * something funny going on. + */ +# ifdef DEBUG + if ( debug & CALLDEBUG ) { + printf( "[findcall]\tbut it's a botch\n" ); + } +# endif DEBUG + length = 1; + continue; + } + } + } +} diff --git a/usr.bin/gprof/vax.h b/usr.bin/gprof/vax.h new file mode 100644 index 0000000..b5fbf35 --- /dev/null +++ b/usr.bin/gprof/vax.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)vax.h 8.1 (Berkeley) 6/6/93 + */ + + /* + * opcode of the `calls' instruction + */ +#define CALLS 0xfb + + /* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 2 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + + /* + * register for pc relative addressing + */ +#define PC 0xf + +enum opermodes { + literal, indexed, reg, regdef, autodec, autoinc, autoincdef, + bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef, + immediate, absolute, byterel, bytereldef, wordrel, wordreldef, + longrel, longreldef +}; +typedef enum opermodes operandenum; + +struct modebyte { + unsigned int regfield:4; + unsigned int modefield:4; +}; + diff --git a/usr.bin/grep/egrep/Makefile b/usr.bin/grep/egrep/Makefile new file mode 100644 index 0000000..556ebfe --- /dev/null +++ b/usr.bin/grep/egrep/Makefile @@ -0,0 +1,17 @@ +# @(#)Makefile 8.1 (Berkeley) 6/27/93 + +# -DSLOWSYS invoke xread() for system time quirk on PDP, others? +# -DNOKANJI default is for Japanese Unix. undef only for raw +# parity-marked search capability, not standard w/grep. +# -DCHINESE for systems using EUC Chinese2 codes +# -Dstrrchr=rindex, -Dstrchr=index as necessary + +PROG= egrep +CFLAGS+=-Dstrrchr=rindex -Dstrchr=index -DNOKANJI +LDADD= -lcompat # must search compat to get spencers early regexp package +MAN1= grep.0 +LINKS= ${BINDIR}/egrep ${BINDIR}/grep ${BINDIR}/egrep ${BINDIR}/fgrep +MLINKS= grep.1 egrep.1 grep.1 fgrep.1 + +.include "../../Makefile.inc" +.include diff --git a/usr.bin/grep/egrep/egrep.c b/usr.bin/grep/egrep/egrep.c new file mode 100644 index 0000000..885965c --- /dev/null +++ b/usr.bin/grep/egrep/egrep.c @@ -0,0 +1,924 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)egrep.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + Hybrid Boyer/Moore/Gosper-assisted 'grep/egrep/fgrep' search, with delta0 + table as in original paper (CACM, October, 1977). No delta1 or delta2. + According to experiment (Horspool, Soft. Prac. Exp., 1982), delta2 is of + minimal practical value. However, to improve for worst case input, + integrating the improved Galil strategies (Apostolico/Giancarlo, SIAM. J. + Comput., Feb. 1986) deserves consideration. + + Method: extract longest metacharacter-free string from expression. + this is done using a side-effect from henry spencer's regcomp(). + use boyer-moore to match such, then pass submatching lines + to either regexp() or standard 'egrep', depending on certain + criteria within execstrategy() below. [this tradeoff is due + to the general slowness of the regexp() nondeterministic + machine on complex expressions, as well as the startup time + of standard 'egrep' on short files.] alternatively, one may + change the vendor-supplied 'egrep' automaton to include + boyer-moore directly. see accompanying writeup for discussion + of kanji expression treatment. + + late addition: apply trickbag for fast match of simple + alternations (sublinear, in common low-cardinality cases). + trap fgrep into this lair. + + gnu additions: -f, newline as |, \< and \> [in regexec()], more + comments. inspire better dfa exec() strategy. + serious testing and help with special cases. + + Algorithm amalgam summary: + + dfa e?grep (aho/thompson) + ndfa regexp() (spencer/aho) + bmg (boyer/moore/gosper) + "superimposed" bmg (jaw) + fgrep (aho/corrasick) + + sorry, but the knuth/morris/pratt machine, horspool's + "frequentist" code, and the rabin/karp matcher, however cute, + just don't cut it for this production. + + James A. Woods Copyright (c) 1986 + NASA Ames Research Center +*/ +#include +#include +#include +#include /* must be henry spencer's version */ +#include +#include +#include "pathnames.h" + +#define MIN(A, B) ((A) > (B) ? (B) : (A)) + +#ifdef SLOWSYS +#define read xread +#endif + +#define BUFSIZE 8192 /* make higher for cray */ +#define PATSIZE 6000 +#define LARGE BUFSIZE + PATSIZE + +#define NALT 7 /* tied to scanf() size in alternate() */ +#define NMUSH 6 /* loosely relates to expected alt length */ + +#define FIRSTFEW 33 /* Always do FIRSTFEW matches with regexec() */ +#define PUNTPERCENT 10 /* After FIRSTFEW, if PUNTPERCENT of the input + * was processed by regexp(), exec std egrep. */ +#define NL '\n' +#define EOS '\0' +#define NONASCII 0200 /* Bit mask for Kanji non-ascii chars */ +#define META "\n^$.[]()?+*|\\" /* egrep meta-characters */ +#define SS2 '\216' /* EUC Katakana (or Chinese2) prefix */ +#define SS3 '\217' /* EUC Kanji2 (or Chinese3) prefix */ + +extern char *optarg; +extern int optind; +char *progname; + +int cflag, iflag, eflag, fflag, lflag, nflag; /* SVID flags */ +int sflag, hflag; /* v7, v8, bsd */ + +int firstflag; /* Stop at first match */ +int grepflag; /* Called as "grep" */ +int fgrepflag; /* Called as "fgrep" */ +int altflag; /* Simple alternation in pattern */ +int boyonly; /* No regexp needed -- all simple */ +int flushflag; +int grepold, egrepold, fgrepold; + +int nalt; /* Number of alternatives */ +int nsuccess; /* 1 for match, 2 for error */ +int altmin; /* Minimum length of all the alternate + * strings */ +int firstfile; /* argv index of first file argument */ +int patind; /* argv index of pattern */ +long nmatch; /* Number of matches in this file */ +long incount, counted; /* Amount of input consumed */ +long rxcount; /* Bytes of input processed by regexec() */ +int boyfound; /* accumulated partial matches (tripped by + * FIRSTFEW) */ +int prevmatch; /* next three lines aid fast -n */ +long nline, prevnline; +char *prevloc; + +regexp *rspencer; +char *pattern; +char *patboy; /* Pattern for simple Boyer-Moore */ +char *patfile; /* Filename containing pattern(s) */ + +int delta0[256]; /* Boyer-Moore algorithm core */ +char cmap[256]; /* Usually 0-255, but if -i, maps upper to + * lower case */ +char str[BUFSIZE + 2]; +int nleftover; +char linetemp[BUFSIZE]; +char *altpat[NALT]; /* alternation component storage */ +int altlen[NALT]; +short altset[NMUSH + 1][256]; +char preamble[200]; /* match prefix (filename, line no.) */ + +int fd; +char * +strchr(), *strrchr(), *strcpy(), *strncpy(), *strpbrk(), *malloc(); +char * +grepxlat(), *fold(), *pfile(), *alternate(), *isolate(); +char *gotamatch(), *kanji(), *linesave(), *submatch(); +char **args; + +main(argc, argv) + int argc; + char *argv[]; +{ + int c, oflag; + int errflag = 0; + + args = argv; + + if ((progname = strrchr(argv[0], '/')) != 0) + progname++; + else + progname = argv[0]; + if (strcmp(progname, "grep") == 0) + grepflag++; + else if (strcmp(progname, "fgrep") == 0) + fgrepflag++; + + oflag = 0; + while ((c = getopt(argc, argv, "bchie:f:lnosvwxy1")) != EOF) { + switch (c) { + + case 'f': + fflag++; + patfile = optarg; + continue; + case 'b': + case 'v': + egrepold++; /* boyer-moore of little help here */ + continue; + case 'c': + cflag++; + continue; + case 'e': + eflag++; + pattern = optarg; + continue; + case 'h': + hflag++; + continue; + case 'o': + oflag++; + continue; + case '1': /* Stop at very first match */ + firstflag++; /* spead freaks only */ + continue; + case 'i': + iflag++; + continue; + case 'l': + lflag++; + continue; + case 'n': + nflag++; + continue; + case 's': + sflag++; + continue; + case 'w': + case 'y': + if (!grepflag) + errflag++; + grepold++; + continue; + case 'x': /* needs more work, like -b above */ + if (!fgrepflag) + errflag++; + fgrepold++; + continue; + case '?': + errflag++; + } + } + if (errflag || ((argc <= optind) && !fflag && !eflag)) { + if (grepflag) +oops("usage: grep [-bchilnosvwy] [-e] pattern [file ...]"); + else if (fgrepflag) +oops("usage: fgrep [-bchilnosvx] {-f patfile | [-e] strings} [file ...]"); + else /* encourage SVID options, though we provide + * others */ +oops("usage: egrep [-bchilnosv] {-f patfile | [-e] pattern} [file ...]"); + } + if (fflag) + pattern = pfile(patfile); + else if (!eflag) { + patind = optind; + pattern = argv[optind++]; + } + + if (!oflag && (argc - optind) <= 1) /* Filename invisible given < 2 files */ + hflag++; + if (pattern[0] == EOS) + kernighan(argv); /* same as it ever was */ + /* + * 'grep/egrep' merger -- "old" grep is called to handle: tagged + * exprs \( \), word matches \< and \>, -w and -y options, char + * classes with '-' at end (egrep bug?), and patterns beginning with + * an asterisk (don't ask why). otherwise, characters meaningful to + * 'egrep' but not to 'grep' are escaped; the entire expr is then + * passed to 'egrep'. + */ + if (grepflag && !grepold) { + if (strindex(pattern, "\\(") >= 0 || + strindex(pattern, "\\<") >= 0 || + strindex(pattern, "\\>") >= 0 || + strindex(pattern, "-]") >= 0 || + pattern[0] == '*') /* grep bug */ + grepold++; + else + pattern = grepxlat(pattern); + } + if (grepold || egrepold || fgrepold) + kernighan(argv); + + if (iflag) + strcpy(pattern, fold(pattern)); + /* + * If the pattern is a plain string, just run boyer-moore. If it + * consists of meta-free alternatives, run "superimposed" bmg. + * Otherwise, find best string, and compile pattern for regexec(). + */ + if (strpbrk(pattern, META) == NULL) { /* do boyer-moore only */ + boyonly++; + patboy = pattern; + } else { + if ((patboy = alternate(pattern)) != NULL) + boyonly++; + else { + if ((patboy = isolate(pattern)) == NULL) + kernighan(argv); /* expr too involved */ +#ifndef NOKANJI + for (c = 0; pattern[c] != EOS; c++) + if (pattern[c] & NONASCII) /* kanji + meta */ + kernighan(argv); +#endif + if ((rspencer = regcomp(pattern)) == NULL) + oops("regcomp failure"); + } + } + gosper(patboy); /* "pre-conditioning is wonderful" + * -- v. strassen */ + + if ((firstfile = optind) >= argc) { + /* Grep standard input */ + if (lflag) /* We don't know its name! */ + exit(1); + egsecute((char *) NULL); + } else { + while (optind < argc) { + egsecute(argv[optind]); + optind++; + if (firstflag && (nsuccess == 1)) + break; + } + } + exit((nsuccess == 2) ? 2 : (nsuccess == 0)); +} + +char * +pfile(pfname) /* absorb expression from file */ + char *pfname; +{ + int fd; + struct stat patstat; + static char *pat; + + if ((fd = open(pfname, O_RDONLY, 0)) < 0) + oops("can't read pattern file"); + if (fstat(fd, &patstat) != 0) + oops("can't stat pattern file"); + if (patstat.st_size > PATSIZE) { + if (fgrepflag) { /* defer to unix version */ + fgrepold++; + return "dummy"; + } else + oops("pattern file too big"); + } + if ((pat = malloc((unsigned) patstat.st_size + 1)) == NULL) + oops("out of memory to read pattern file"); + if (patstat.st_size != read(fd, pat, (int)patstat.st_size)) + oops("error reading pattern file"); + (void) close(fd); + + pat[patstat.st_size] = EOS; + if (pat[patstat.st_size - 1] == NL) /* NOP for egrep; helps grep */ + pat[patstat.st_size - 1] = EOS; + + if (nlcount(pat, &pat[patstat.st_size]) > NALT) { + if (fgrepflag) + fgrepold++; /* "what's it all about, alfie?" */ + else + egrepold++; + } + return (pat); +} + +egsecute(file) + char *file; +{ + extern int errno; + + if (file == NULL) + fd = 0; + else if ((fd = open(file, O_RDONLY, 0)) <= 0) { + fprintf(stderr, + "%s: %s: %s\n", progname, file, strerror(errno)); + nsuccess = 2; + return; + } + chimaera(file, patboy); + + if (!boyonly && !flushflag && file != NULL) + flushmatches(); + if (file != NULL) + close(fd); +} + +chimaera(file, pat) /* "reach out and boyer-moore search someone" */ + char *file, *pat; /* -- soon-to-be-popular bumper sticker */ +{ + register char *k, *strend, *s; + register int j, count; + register int *deltazero = delta0; + int patlen = altmin; + char *t; + + nleftover = boyfound = flushflag = 0; + nline = 1L; + prevmatch = 0; + nmatch = counted = rxcount = 0L; + + while ((count = read(fd, str + nleftover, BUFSIZE - nleftover)) > 0) { + + counted += count; + strend = linesave(str, count); + + for (k = str + patlen - 1; k < strend;) { + /* + * for a large class of patterns, upwards of 80% of + * match time is spent on the next line. we beat + * existing microcode (vax 'matchc') this way. + */ + while ((k += deltazero[*(unsigned char *) k]) < strend); + if (k < (str + LARGE)) + break; + k -= LARGE; + + if (altflag) { + /* + * Parallel Boyer-Moore. Check whether each + * of the previous chars COULD be + * from one of the alternative strings. + */ + s = k - 1; + j = altmin; + while (altset[--j][(unsigned char) + cmap[*(unsigned char *) s--]]); + /* + * quick test fails. in this life, compare + * 'em all. but, a "reverse trie" would + * attenuate worst case (linear w/delta2?). + */ + if (--j < 0) { + count = nalt - 1; + do { + s = k; + j = altlen[count]; + t = altpat[count]; + + while + (cmap[*(unsigned char *) s--] + == t[--j]); + if (j < 0) + break; + } + while (count--); + } + } else { + /* One string -- check it */ + j = patlen - 1; + s = k - 1; + while (cmap[*(unsigned char *) s--] == pat[--j]); + } + /* + * delta-less shortcut for literati. short shrift for + * genetic engineers? + */ + if (j >= 0) { + k++; /* no match; restart next char */ + continue; + } + k = submatch(file, pat, str, strend, k, count); + if (k == NULL) + return; + } + if (nflag) { + if (prevmatch) + nline = prevnline + nlcount(prevloc, k); + else + nline = nline + nlcount(str, k); + prevmatch = 0; + } + strncpy(str, linetemp, nleftover); + } + if (cflag) { + /* Bug from old grep: -c overrides -h. We fix the bug. */ + if (!hflag) + printf("%s:", file); + printf("%ld\n", nmatch); + } +} + +char * +linesave(str, count) /* accumulate partial line at end of buffer */ + char str[]; + register int count; +{ + register int j; + + count += nleftover; + if (count != BUFSIZE && fd != 0) + str[count++] = NL; /* insurance for broken last line */ + str[count] = EOS; + for (j = count - 1; str[j] != NL && j >= 0;) + j--; + /* + * break up these lines: long line (> BUFSIZE), last line of file, or + * short return from read(), as from tee(1) input + */ + if (j < 0 && (count == (BUFSIZE - nleftover))) { + str[count++] = NL; + str[count] = EOS; + linetemp[0] = EOS; + nleftover = 0; + return (str + count); + } else { + nleftover = count - j - 1; + strncpy(linetemp, str + j + 1, nleftover); + return (str + j); + } +} + +/* + * Process partial match. First check for mis-aligned Kanji, then match line + * against full compiled r.e. if statistics do not warrant handing off to + * standard egrep. + */ +char * +submatch(file, pat, str, strend, k, altindex) + char file[], pat[], str[]; + register char *strend, *k; + int altindex; +{ + register char *s; + char *t, c; + + t = k; + s = ((altflag) ? k - altlen[altindex] + 1 : k - altmin + 1); +#ifndef NOKANJI + c = ((altflag) ? altpat[altindex][0] : pat[0]); + if (c & NONASCII) + if ((s = kanji(str, s, k)) == NULL) + return (++k); /* reject false kanji */ +#endif + do; + while (*s != NL && --s >= str); + k = s + 1; /* now at line start */ + + if (boyonly) + return (gotamatch(file, k)); + + incount = counted - (strend - k); + if (boyfound++ == FIRSTFEW) + execstrategy(file); + + s = t; + do + rxcount++; + while (*s++ != NL); + *--s = EOS; + /* + * "quick henry -- the flit" (after theodor geisel) + */ + if (regexec(rspencer, ((iflag) ? fold(k) : k)) == 1) { + *s = NL; + if (gotamatch(file, k) == NULL) + return (NULL); + } + *s = NL; + return (s + 1); +} + +#ifndef NOKANJI +/* + * EUC code disambiguation -- scan backwards to first 7-bit code, while + * counting intervening 8-bit codes. If odd, reject unaligned Kanji pattern. + * SS2/3 checks are for intermixed Japanase Katakana or Kanji2. + */ +char * +kanji(str, s, k) + register char *str, *s, *k; +{ + register int j = 0; + + for (s--; s >= str; s--) { + if (*s == SS2 || *s == SS3 || (*s & NONASCII) == 0) + break; + j++; + } +#ifndef CHINESE + if (*s == SS2) + j -= 1; +#endif CHINESE + return ((j & 01) ? NULL : k); +} +#endif + +/* + * Compute "Boyer-Moore" delta table -- put skip distance in delta0[c] + */ +gosper(pattern) + char *pattern; /* ... HAKMEM lives ... */ +{ + register int i, j; + unsigned char c; + + /* Make one-string case look like simple alternatives case */ + if (!altflag) { + nalt = 1; + altmin = altlen[0] = strlen(pattern); + altpat[0] = pattern; + } + /* For chars that aren't in any string, skip by string length. */ + for (j = 0; j < 256; j++) { + delta0[j] = altmin; + cmap[j] = j; /* Sneak in initialization of cmap */ + } + + /* For chars in a string, skip distance from char to end of string. */ + /* (If char appears more than once, skip minimum distance.) */ + for (i = 0; i < nalt; i++) + for (j = 0; j < altlen[i] - 1; j++) { + c = altpat[i][j]; + delta0[c] = MIN(delta0[c], altlen[i] - j - 1); + if (iflag && islower((int) c)) + delta0[toupper((int) c)] = delta0[c]; + } + + /* For last char of each string, fall out of search loop. */ + for (i = 0; i < nalt; i++) { + c = altpat[i][altlen[i] - 1]; + delta0[c] = LARGE; + if (iflag && islower((int) c)) + delta0[toupper((int) c)] = LARGE; + } + if (iflag) + for (j = 'A'; j <= 'Z'; j++) + cmap[j] = tolower((int) j); +} + +/* + * Print, count, or stop on full match. Result is either the location for + * continued search, or NULL to stop. + */ +char * +gotamatch(file, s) + register char *file, *s; +{ + char *savematch(); + int squirrel = 0; /* nonzero to squirrel away FIRSTFEW matches */ + + nmatch++; + nsuccess = 1; + if (!boyonly && boyfound <= FIRSTFEW && file != NULL) + squirrel = 1; + + if (sflag) + return (NULL); /* -s usurps all flags (unlike some versions) */ + if (cflag) { /* -c overrides -l, we guess */ + do; + while (*s++ != NL); + } else if (lflag) { + puts(file); + return (NULL); + } else { + if (!hflag) + if (!squirrel) + printf("%s:", file); + else + (void)sprintf(preamble, "%s:", file); + if (nflag) { + if (prevmatch) + prevnline = prevnline + nlcount(prevloc, s); + else + prevnline = nline + nlcount(str, s); + prevmatch = 1; + + if (!squirrel) + printf("%ld:", prevnline); + else + (void)sprintf(preamble + strlen(preamble), + "%ld:", prevnline); + } + if (!squirrel) { + do + putchar(*s); + while (*s++ != NL); + } else + s = savematch(s); + + if (nflag) + prevloc = s - 1; + } + return ((firstflag && !cflag) ? NULL : s); +} + +char * +fold(line) + char *line; +{ + static char fline[BUFSIZE]; + register char *s, *t = fline; + + for (s = line; *s != EOS; s++) + *t++ = (isupper((int) *s) ? (char) tolower((int) *s) : *s); + *t = EOS; + return (fline); +} + +strindex(s, t) /* the easy way, as in K&P, p. 192 */ + char *s, *t; +{ + int i, n; + + n = strlen(t); + for (i = 0; s[i] != '\0'; i++) + if (strncmp(s + i, t, n) == 0) + return (i); + return (-1); +} + +char * +grepxlat(pattern) /* grep pattern meta conversion */ + char *pattern; +{ + register char *p, *s; + static char newpat[BUFSIZE]; + + for (s = newpat, p = pattern; *p != EOS;) { + if (*p == '\\') { /* skip escapes ... */ + *s++ = *p++; + if (*p) + *s++ = *p++; + } else if (*p == '[') { /* ... and char classes */ + while (*p != EOS && *p != ']') + *s++ = *p++; + } else if (strchr("+?|()", *p) != NULL) { + *s++ = '\\'; /* insert protection */ + *s++ = *p++; + } else + *s++ = *p++; + } + *s = EOS; + grepflag = ((patind) ? 0 : 1); + return (newpat); +} + +/* + * Test for simple alternation. Result is NULL if it's not so simple, or is + * a pointer to the first string if it is. Warning: sscanf size is a + * fixpoint, beyond which the speedup linearity starts to break down. In the + * wake of the elegant aho/corrasick "trie"-based fgrep, generalizing + * altpat[] to arbitrary size is not useful. + */ +char * +alternate(regexpr) + char *regexpr; +{ + register int i, j; + register char *start, *stop; + unsigned char c; + + if (fgrepflag && strchr(regexpr, '|')) + return (NULL); + + /* + * break pattern up into altpat array; delimit on newline, bar, + * or EOS. We know we won't overflow, we've already checked the + * number of patterns we're going to find against NALT. + * Also, set length of pattern and find minimum pattern length. + */ + nalt = 0; + altmin = NMUSH; + for (start = stop = regexpr;; ++stop) + if (!*stop || *stop == '|' || *stop == NL) { + altlen[nalt] = j = stop - start; + if (j < altmin) + altmin = j; + if (!(altpat[nalt] = malloc((u_int)(j + 1)))) + oops("out of memory"); + bcopy(start, altpat[nalt], j); + altpat[nalt][j] = EOS; + ++nalt; + if (!*stop) + break; + if (nalt == NALT) + return(NULL); + if (*stop == NL) + *stop = '|'; + start = stop + 1; + } + if (!fgrepflag) { + if (strchr(regexpr, '|') == NULL || regexpr[0] == '|') + return (NULL); + if (strpbrk(regexpr, "^$.[]()?+*\\") != NULL + || strindex(regexpr, "||") >= 0) + return (NULL); + } + + if (nalt > 1) { /* build superimposed "pre-match" sets per + * char */ + altflag++; + for (j = 0; j < nalt; j++) + for (i = 0; i < altmin; i++) { + c = altpat[j][altlen[j] - altmin + i]; + altset[i + 1][c] = 1; /* offset for sentinel */ + } + } + return (altpat[0]); +} + +/* + * Grapple with the dfa (std egrep) vs. ndfa (regexp) tradeoff. Criteria to + * determine whether to use dfa-based egrep: We do FIRSTFEW matches with + * regexec(). If Boyer-Moore up to now matched more than PUNTPERCENT + * of the input, the r.e. is likely to be underspecified, so do old *grep, + * which is faster on complex patterns than regexp(). At FIRSTFEW, + * dump the saved matches collected by savematch(). They are saved + * so that a "PUNT" can "rewind" to ignore them. Stdin is problematic, + * since it's hard to rewind. + */ + +execstrategy(file) + char *file; +{ + int pctmatch; + + pctmatch = (100 * rxcount) / incount; + if (pctmatch > PUNTPERCENT && file != NULL) + kernighan(args); + if (file != NULL) + flushmatches(); +} + +nlcount(bstart, bstop) /* flail interval to totalize newlines. */ + char *bstart, *bstop; +{ + register char *s = bstart; + register char *t = bstop; + register int count = 0; + + do { /* loop unroll for older architectures */ + if (*t == NL) /* ... ask ames!jaw for sample code */ + count++; + } while (t-- > s); + + return (count); +} + +char * +isolate(regexpr) /* isolate longest metacharacter-free string */ + char *regexpr; +{ + char *dummyexpr; + + /* + * We add (.)* because Henry's regcomp only figures regmust if it + * sees a leading * pattern. Foo! + */ + dummyexpr = malloc((unsigned) strlen(regexpr) + 5); + (void)sprintf(dummyexpr, "(.)*%s", regexpr); + if ((rspencer = regcomp(dummyexpr)) == NULL) + kernighan(args); + return (rspencer->regmust); +} + +char *matches[FIRSTFEW]; +static int mcount = 0; + +char * +savematch(s) /* horde matches during statistics gathering */ + register char *s; +{ + char *p; + char *start = s; + int msize = 0; + int psize = strlen(preamble); + + while (*s++ != NL) + msize++; + *--s = EOS; + + p = malloc((unsigned) msize + 1 + psize); + strcpy(p, preamble); + strcpy(p + psize, start); + matches[mcount++] = p; + + preamble[0] = 0; + *s = NL; + return (s); +} + +flushmatches() +{ + int n; + + flushflag = 1; + for (n = 0; n < mcount; n++) + printf("%s\n", matches[n]); + mcount = 0; +} + +oops(message) + char *message; +{ + fprintf(stderr, "%s: %s\n", progname, message); + exit(2); +} + +kernighan(args) /* "let others do the hard part ..." */ + char *args[]; +{ + /* + * We may have already run grep on some of the files; remove them + * from the arg list we pass on. Note that we can't delete them + * totally because the number of file names affects the output + * (automatic -h). + */ + /* better would be fork/exec per punted file -- jaw */ + + while (firstfile && optind > firstfile) + args[firstfile++] = _PATH_DEVNULL; + if (patind) + args[patind] = pattern; + (void) fflush(stdout); + + if (grepflag) + execvp(_PATH_GREPSTD, args), oops("can't exec old 'grep'"); + else if (fgrepflag) + execvp(_PATH_FGREPSTD, args), oops("can't exec old 'fgrep'"); + else + execvp(_PATH_EGREPSTD, args), oops("can't exec old 'egrep'"); +} diff --git a/usr.bin/grep/egrep/grep.1 b/usr.bin/grep/egrep/grep.1 new file mode 100644 index 0000000..771cc8c --- /dev/null +++ b/usr.bin/grep/egrep/grep.1 @@ -0,0 +1,250 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)grep.1 8.3 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt GREP 1 +.Os +.Sh NAME +.Nm grep +.Nd file pattern searcher +.Sh SYNOPSIS +.Nm grep +.Op Fl bchilnosvw +.Op Fl e Ar pattern +.Op Ar +.Nm egrep +.Op Fl bchilnosv +.Op Fl e Ar pattern +.Op Fl f Ar pattern_file +.Op Ar +.Nm fgrep +.Op Fl bchilnosvx +.Op Fl e Ar pattern +.Op Fl f Ar pattern_file +.Op Ar +.Sh DESCRIPTION +The +.Nm grep +utilities search the given input files selecting lines +which match one or more patterns; the type of patterns is controlled +by the options specified. +By default, a pattern +matches an input line if any regular expression (RE) in the +pattern matches the input line without its trailing . +A null RE matches every line. +Each input line that matches at +least one of the patterns is written to the standard output. +.Pp +For simple patterns or +.Xr ex 1 +or +.Xr ed 1 +style regular expressions, the +.Nm grep +utility is used. +The +.Nm egrep +utility +can handle extended regular expressions and +embedded s in patterns. +The +.Nm fgrep +utility is quick but can handle only fixed strings. +A fixed string +is a string of characters, +each character +is matched only by itself. +The pattern +value can consist of multiple lines with +embedded s. +In this case, the s +act as alternation characters, allowing any of the +pattern lines to match a portion of the input. +.Pp +The following options are available: +.Pp +.Bl -tag -width indent +.It Fl b +The block number on the disk in which a matched pattern is located +is displayed in front of the respective matched line. +.It Fl c +Only a count of selected lines is written to standard +output. +.It Fl e Ar expression +Specify a pattern used during the search of the +input. +Multiple +.Fl e +options can be used to specify +multiple patterns; an input line is selected if it +matches any of the specified patterns. +.It Fl f Ar pattern_file +The pattern is read from the file named by the +pathname pattern_file. +Trailing newlines +in the pattern_file are ignored. +.Pf ( Nm Egrep +and +.Nm fgrep +only). +.It Fl h +Never print filename headers with output lines. +.It Fl i +The case of letters is ignored in making comparisons \- that is, upper and +lower case are considered identical. +.It Fl l +Only the names of files containing selected lines +are written to standard output. +Pathnames are +listed once per file searched. +If the standard +input is searched, the pathname +.Sq Fl +is written. +.It Fl n +Each output line is preceded by its relative line +number in the file; each file starting at line 1. +The line number counter is reset for each file processed. +This option is ignored if +.Fl c , +.Fl l , +or +.Fl s +is +specified. +.It Fl o +Always print filename headers with output lines. +.It Fl s +Silent mode. Nothing is printed (except error messages). +This is useful for checking the error status. +.It Fl v +Selected lines are those +.Em not +matching the specified +patterns. +.It Fl x +Only input lines selected against an entire fixed +string or regular expression are considered to be +matching lines. +.Pf ( Nm Fgrep +only). +.It Fl w +The expression is searched for as a word +(as if surrounded by `\e<' and `\e>', see +.Xr ex 1 . ) +.Pf ( Nm Grep +only) +.Pp +.El +If no file arguments are specified, the +standard input is used. +.Pp +The +.Nm grep +utility exits with one of the following values: +.Pp +.Bl -tag -width flag -compact +.It Li 0 +One or more lines were selected. +.It Li 1 +No lines were selected. +.It Li >1 +An error occurred. +.El +.Sh EXTENDED REGULAR EXPRESSIONS +The following characters are interpreted by +.Nm egrep : +.Pp +.Bl -tag -width flag -compact +.It Cm \&$ +Align the match from the end of the line. +.It Cm \&^ +Align the match from the beginning of the line. +.It Cm \&| +Add another pattern (see example below). +.It Cm \&? +Match 1 or less sequential repetitions of the pattern. +.It Cm \&+ +Match 1 or more sequential repetitions of the pattern. +.It Cm \&* +Match 0 or more sequential repetitions of the pattern. +.It Cm \&[] +Match any single character or range of characters +enclosed in the brackets. +.It Cm \&\e +Escape special characters which have meaning to +.Nm egrep , +the set of {$,.,^,[,],|,?,+,*,(,)}. +.El +.Sh EXAMPLES +To find all occurrences of the word patricia in a file: +.Pp +.Dl grep patricia myfile +.Pp +To find all occurrences of the pattern +.Ql \&.Pp +at the beginning of a line: +.Pp +.Dl grep '^\e.Pp' +.Pp +The apostrophes assure the entire expression is evaluated by +.Nm grep +instead of by the +users shell. +The carat or hat +.Ql Li \&^ +means +.Em from the beginning of a line , +and the +.Ql Li \&\e +escapes the +.Ql Li \&. +which would otherwise match any character. +.Pp +A simple example of an extended regular expression: +.Pp +.Dl egrep '19|20|25' calendar +.Pp +Peruses the file calendar looking for either 19, 20 +or 25. +.Sh SEE ALSO +.Xr ed 1 , +.Xr ex 1 , +.Xr sed 1 +.Sh HISTORY +The +.Nm grep +command appeared in +.At v6 . +.Sh BUGS +Lines are limited to 256 characters; longer lines are truncated. diff --git a/usr.bin/grep/egrep/pathnames.h b/usr.bin/grep/egrep/pathnames.h new file mode 100644 index 0000000..a25b3dc --- /dev/null +++ b/usr.bin/grep/egrep/pathnames.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_EGREPSTD "/usr/libexec/old.egrep" +#define _PATH_GREPSTD "/usr/libexec/old.bin.grep" +#define _PATH_FGREPSTD "/usr/libexec/old.fgrep" diff --git a/usr.bin/head/Makefile b/usr.bin/head/Makefile new file mode 100644 index 0000000..b0b911e --- /dev/null +++ b/usr.bin/head/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= head + +.include diff --git a/usr.bin/head/head.1 b/usr.bin/head/head.1 new file mode 100644 index 0000000..2e47515 --- /dev/null +++ b/usr.bin/head/head.1 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)head.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt HEAD 1 +.Os BSD 3 +.Sh NAME +.Nm head +.Nd display first lines of a file +.Sh SYNOPSIS +.Nm head +.Op Fl n Ar count +.Op Ar file ... +.Sh DESCRIPTION +This filter displays the first +.Ar count +lines of each of the specified files, or of the standard input if no +files are specified. +If +.Ar count +is omitted it defaults to 10. +.Pp +If more than a single file is specified, each file is preceded by a +header consisting of the string +.Dq ==> XXX <== +where +.Dq XXX +is the name of the file. +.Pp +The +.Nm head +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr tail 1 +.Sh HISTORY +The +.Nm head +command appeared in +.Bx 3.0 . diff --git a/usr.bin/head/head.c b/usr.bin/head/head.c new file mode 100644 index 0000000..e33a3c2 --- /dev/null +++ b/usr.bin/head/head.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1980, 1987, 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 copyright[] = +"@(#) Copyright (c) 1980, 1987, 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)head.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +/* + * head - give the first few lines of a stream or of each of a set of files + * + * Bill Joy UCB August 24, 1977 + */ + +void err __P((int, const char *, ...)); +void head __P((FILE *, int)); +void obsolete __P((char *[])); +void usage __P((void)); + +int eval; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int ch; + FILE *fp; + int first, linecnt; + char *ep; + + obsolete(argv); + linecnt = 10; + while ((ch = getopt(argc, argv, "n:")) != EOF) + switch(ch) { + case 'n': + linecnt = strtol(optarg, &ep, 10); + if (*ep || linecnt <= 0) + err(1, "illegal line count -- %s", optarg); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (*argv) + for (first = 1; *argv; ++argv) { + if ((fp = fopen(*argv, "r")) == NULL) { + err(0, "%s: %s", *argv, strerror(errno)); + continue; + } + if (argc > 1) { + (void)printf("%s==> %s <==\n", + first ? "" : "\n", *argv); + first = 0; + } + head(fp, linecnt); + (void)fclose(fp); + } + else + head(stdin, linecnt); + exit(eval); +} + +void +head(fp, cnt) + FILE *fp; + register int cnt; +{ + register int ch; + + while (cnt--) + while ((ch = getc(fp)) != EOF) { + if (putchar(ch) == EOF) + err(1, "stdout: %s", strerror(errno)); + if (ch == '\n') + break; + } +} + +void +obsolete(argv) + char *argv[]; +{ + char *ap; + + while (ap = *++argv) { + /* Return if "--" or not "-[0-9]*". */ + if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1])) + return; + if ((ap = malloc(strlen(*argv) + 2)) == NULL) + err(1, "%s", strerror(errno)); + ap[0] = '-'; + ap[1] = 'n'; + (void)strcpy(ap + 2, *argv + 1); + *argv = ap; + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: head [-n lines] [file ...]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(int fatal, const char *fmt, ...) +#else +err(fatal, fmt, va_alist) + int fatal; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "head: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (fatal) + exit(1); + eval = 1; +} diff --git a/usr.bin/hexdump/Makefile b/usr.bin/hexdump/Makefile new file mode 100644 index 0000000..5a9e87a --- /dev/null +++ b/usr.bin/hexdump/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= hexdump +SRCS= conv.c display.c hexdump.c hexsyntax.c odsyntax.c parse.c +MAN1= hexdump.0 od.0 +LINKS= ${BINDIR}/hexdump ${BINDIR}/od + +.include diff --git a/usr.bin/hexdump/conv.c b/usr.bin/hexdump/conv.c new file mode 100644 index 0000000..daae174 --- /dev/null +++ b/usr.bin/hexdump/conv.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)conv.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include "hexdump.h" + +void +conv_c(pr, p) + PR *pr; + u_char *p; +{ + extern int deprecated; + char buf[10], *str; + + switch(*p) { + case '\0': + str = "\\0"; + goto strpr; + /* case '\a': */ + case '\007': + if (deprecated) /* od didn't know about \a */ + break; + str = "\\a"; + goto strpr; + case '\b': + str = "\\b"; + goto strpr; + case '\f': + str = "\\f"; + goto strpr; + case '\n': + str = "\\n"; + goto strpr; + case '\r': + str = "\\r"; + goto strpr; + case '\t': + str = "\\t"; + goto strpr; + case '\v': + if (deprecated) + break; + str = "\\v"; + goto strpr; + default: + break; + } + if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + (void)sprintf(str = buf, "%03o", (int)*p); +strpr: *pr->cchar = 's'; + (void)printf(pr->fmt, str); + } +} + +void +conv_u(pr, p) + PR *pr; + u_char *p; +{ + extern int deprecated; + static char *list[] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "lf", "vt", "ff", "cr", "so", "si", + "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + }; + + /* od used nl, not lf */ + if (*p <= 0x1f) { + *pr->cchar = 's'; + if (deprecated && *p == 0x0a) + (void)printf(pr->fmt, "nl"); + else + (void)printf(pr->fmt, list[*p]); + } else if (*p == 0x7f) { + *pr->cchar = 's'; + (void)printf(pr->fmt, "del"); + } else if (deprecated && *p == 0x20) { /* od replaced space with sp */ + *pr->cchar = 's'; + (void)printf(pr->fmt, " sp"); + } else if (isprint(*p)) { + *pr->cchar = 'c'; + (void)printf(pr->fmt, *p); + } else { + *pr->cchar = 'x'; + (void)printf(pr->fmt, (int)*p); + } +} diff --git a/usr.bin/hexdump/display.c b/usr.bin/hexdump/display.c new file mode 100644 index 0000000..8078e71 --- /dev/null +++ b/usr.bin/hexdump/display.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "hexdump.h" + +enum _vflag vflag = FIRST; + +static off_t address; /* address/offset in stream */ +static off_t eaddress; /* end address */ + +static inline void print __P((PR *, u_char *)); + +void +display() +{ + extern FU *endfu; + register FS *fs; + register FU *fu; + register PR *pr; + register int cnt; + register u_char *bp; + off_t saveaddress; + u_char savech, *savebp; + + while (bp = get()) + for (fs = fshead, savebp = bp, saveaddress = address; fs; + fs = fs->nextfs, bp = savebp, address = saveaddress) + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->flags&F_IGNORE) + break; + for (cnt = fu->reps; cnt; --cnt) + for (pr = fu->nextpr; pr; address += pr->bcnt, + bp += pr->bcnt, pr = pr->nextpr) { + if (eaddress && address >= eaddress && + !(pr->flags & (F_TEXT|F_BPAD))) + bpad(pr); + if (cnt == 1 && pr->nospace) { + savech = *pr->nospace; + *pr->nospace = '\0'; + } + print(pr, bp); + if (cnt == 1 && pr->nospace) + *pr->nospace = savech; + } + } + if (endfu) { + /* + * If eaddress not set, error or file size was multiple of + * blocksize, and no partial block ever found. + */ + if (!eaddress) { + if (!address) + return; + eaddress = address; + } + for (pr = endfu->nextpr; pr; pr = pr->nextpr) + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)eaddress); + break; + case F_TEXT: + (void)printf(pr->fmt); + break; + } + } +} + +static inline void +print(pr, bp) + PR *pr; + u_char *bp; +{ + double f8; + float f4; + int16_t s2; + int8_t s8; + int32_t s4; + u_int16_t u2; + u_int32_t u4; + u_int64_t u8; + + switch(pr->flags) { + case F_ADDRESS: + (void)printf(pr->fmt, (quad_t)address); + break; + case F_BPAD: + (void)printf(pr->fmt, ""); + break; + case F_C: + conv_c(pr, bp); + break; + case F_CHAR: + (void)printf(pr->fmt, *bp); + break; + case F_DBL: + switch(pr->bcnt) { + case 4: + bcopy(bp, &f4, sizeof(f4)); + (void)printf(pr->fmt, f4); + break; + case 8: + bcopy(bp, &f8, sizeof(f8)); + (void)printf(pr->fmt, f8); + break; + } + break; + case F_INT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (quad_t)*bp); + break; + case 2: + bcopy(bp, &s2, sizeof(s2)); + (void)printf(pr->fmt, (quad_t)s2); + break; + case 4: + bcopy(bp, &s4, sizeof(s4)); + (void)printf(pr->fmt, (quad_t)s4); + break; + case 8: + bcopy(bp, &s8, sizeof(s8)); + (void)printf(pr->fmt, s8); + break; + } + break; + case F_P: + (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); + break; + case F_STR: + (void)printf(pr->fmt, (char *)bp); + break; + case F_TEXT: + (void)printf(pr->fmt); + break; + case F_U: + conv_u(pr, bp); + break; + case F_UINT: + switch(pr->bcnt) { + case 1: + (void)printf(pr->fmt, (u_quad_t)*bp); + break; + case 2: + bcopy(bp, &u2, sizeof(u2)); + (void)printf(pr->fmt, (u_quad_t)u2); + break; + case 4: + bcopy(bp, &u4, sizeof(u4)); + (void)printf(pr->fmt, (u_quad_t)u4); + break; + case 8: + bcopy(bp, &u8, sizeof(u8)); + (void)printf(pr->fmt, u8); + break; + } + break; + } +} + +void +bpad(pr) + PR *pr; +{ + static char *spec = " -0+#"; + register char *p1, *p2; + + /* + * Remove all conversion flags; '-' is the only one valid + * with %s, and it's not useful here. + */ + pr->flags = F_BPAD; + pr->cchar[0] = 's'; + pr->cchar[1] = '\0'; + for (p1 = pr->fmt; *p1 != '%'; ++p1); + for (p2 = ++p1; *p1 && index(spec, *p1); ++p1); + while (*p2++ = *p1++); +} + +static char **_argv; + +u_char * +get() +{ + extern enum _vflag vflag; + extern int length; + static int ateof = 1; + static u_char *curp, *savp; + register int n; + int need, nread; + u_char *tmpp; + + if (!curp) { + curp = emalloc(blocksize); + savp = emalloc(blocksize); + } else { + tmpp = curp; + curp = savp; + savp = tmpp; + address += blocksize; + } + for (need = blocksize, nread = 0;;) { + /* + * if read the right number of bytes, or at EOF for one file, + * and no other files are available, zero-pad the rest of the + * block and set the end flag. + */ + if (!length || ateof && !next((char **)NULL)) { + if (need == blocksize) + return((u_char *)NULL); + if (vflag != ALL && !bcmp(curp, savp, nread)) { + if (vflag != DUP) + (void)printf("*\n"); + return((u_char *)NULL); + } + bzero((char *)curp + nread, need); + eaddress = address + nread; + return(curp); + } + n = fread((char *)curp + nread, sizeof(u_char), + length == -1 ? need : MIN(length, need), stdin); + if (!n) { + if (ferror(stdin)) + (void)fprintf(stderr, "hexdump: %s: %s\n", + _argv[-1], strerror(errno)); + ateof = 1; + continue; + } + ateof = 0; + if (length != -1) + length -= n; + if (!(need -= n)) { + if (vflag == ALL || vflag == FIRST || + bcmp(curp, savp, blocksize)) { + if (vflag == DUP || vflag == FIRST) + vflag = WAIT; + return(curp); + } + if (vflag == WAIT) + (void)printf("*\n"); + vflag = DUP; + address += blocksize; + need = blocksize; + nread = 0; + } + else + nread += n; + } +} + +extern off_t skip; /* bytes to skip */ + +int +next(argv) + char **argv; +{ + extern int exitval; + static int done; + int statok; + + if (argv) { + _argv = argv; + return(1); + } + for (;;) { + if (*_argv) { + if (!(freopen(*_argv, "r", stdin))) { + (void)fprintf(stderr, "hexdump: %s: %s\n", + *_argv, strerror(errno)); + exitval = 1; + ++_argv; + continue; + } + statok = done = 1; + } else { + if (done++) + return(0); + statok = 0; + } + if (skip) + doskip(statok ? *_argv : "stdin", statok); + if (*_argv) + ++_argv; + if (!skip) + return(1); + } + /* NOTREACHED */ +} + +void +doskip(fname, statok) + char *fname; + int statok; +{ + register int cnt; + struct stat sb; + + if (statok) { + if (fstat(fileno(stdin), &sb)) + err("%s: %s", fname, strerror(errno)); + if (S_ISREG(sb.st_mode) && skip >= sb.st_size) { + address += sb.st_size; + skip -= sb.st_size; + return; + } + } + if (S_ISREG(sb.st_mode)) { + if (fseek(stdin, skip, SEEK_SET)) + err("%s: %s", fname, strerror(errno)); + address += skip; + skip = 0; + } else { + for (cnt = 0; cnt < skip; ++cnt) + if (getchar() == EOF) + break; + address += cnt; + skip -= cnt; + } +} + +void * +emalloc(size) + int size; +{ + void *p; + + if ((p = malloc((u_int)size)) == NULL) + nomem(); + bzero(p, size); + return(p); +} + +void +nomem() +{ + err("%s", strerror(errno)); +} diff --git a/usr.bin/hexdump/hexdump.1 b/usr.bin/hexdump/hexdump.1 new file mode 100644 index 0000000..7161beb --- /dev/null +++ b/usr.bin/hexdump/hexdump.1 @@ -0,0 +1,324 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)hexdump.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt HEXDUMP 1 +.Os +.Sh NAME +.Nm hexdump +.Nd ascii, decimal, hexadecimal, octal dump +.Sh SYNOPSIS +.Nm hexdump +.Op Fl bcdovx +.Op Fl e Ar format_string +.Op Fl f Ar format_file +.Op Fl n Ar length +.Bk -words +.Op Fl s Ar skip +.Ek +.Ar file ... +.Sh DESCRIPTION +The hexdump utility is a filter which displays the specified files, or +the standard input, if no files are specified, in a user specified +format. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl b +.Em One-byte octal display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, zero-filled, bytes of input data, +in octal, per line. +.It Fl c +.Em One-byte character display . +Display the input offset in hexadecimal, followed by sixteen +space-separated, three column, space-filled, characters of input +data per line. +.It Fl d +.Em Two-byte decimal display. +Display the input offset in hexadecimal, followed by eight +space-separated, five column, zero-filled, two-byte units +of input data, in unsigned decimal, per line. +.It Fl e Ar format_string +Specify a format string to be used for displaying data. +.It Fl f Ar format_file +Specify a file that contains one or more newline separated format strings. +Empty lines and lines whose first non-blank character is a hash mark +.Pf ( Cm \&# ) +are ignored. +.It Fl n Ar length +Interpret only +.Ar length +bytes of input. +.It Fl o +.Em Two-byte octal display. +Display the input offset in hexadecimal, followed by eight +space-separated, six column, zero-filled, two byte quantities of +input data, in octal, per line. +.It Fl s Ar offset +Skip +.Ar offset +bytes from the beginning of the input. +By default, +.Ar offset +is interpreted as a decimal number. +With a leading +.Cm 0x +or +.Cm 0X , +.Ar offset +is interpreted as a hexadecimal number, +otherwise, with a leading +.Cm 0 , +.Ar offset +is interpreted as an octal number. +Appending the character +.Cm b , +.Cm k , +or +.Cm m +to +.Ar offset +causes it to be interpreted as a multiple of +.Li 512 , +.Li 1024 , +or +.Li 1048576 , +respectively. +.It Fl v +The +.Fl v +option causes hexdump to display all input data. +Without the +.Fl v +option, any number of groups of output lines, which would be +identical to the immediately preceding group of output lines (except +for the input offsets), are replaced with a line comprised of a +single asterisk. +.It Fl x +.Em Two-byte hexadecimal display. +Display the input offset in hexadecimal, followed by eight, space +separated, four column, zero-filled, two-byte quantities of input +data, in hexadecimal, per line. +.El +.Pp +For each input file, +.Nm hexdump +sequentially copies the input to standard output, transforming the +data according to the format strings specified by the +.Fl e +and +.Fl f +options, in the order that they were specified. +.Ss Formats +A format string contains any number of format units, separated by +whitespace. +A format unit contains up to three items: an iteration count, a byte +count, and a format. +.Pp +The iteration count is an optional positive integer, which defaults to +one. +Each format is applied iteration count times. +.Pp +The byte count is an optional positive integer. +If specified it defines the number of bytes to be interpreted by +each iteration of the format. +.Pp +If an iteration count and/or a byte count is specified, a single slash +must be placed after the iteration count and/or before the byte count +to disambiguate them. +Any whitespace before or after the slash is ignored. +.Pp +The format is required and must be surrounded by double quote +(" ") marks. +It is interpreted as a fprintf-style format string (see +.Xr fprintf 3 ) , +with the +following exceptions: +.Bl -bullet -offset indent +.It +An asterisk (*) may not be used as a field width or precision. +.It +A byte count or field precision +.Em is +required for each ``s'' conversion +character (unlike the +.Xr fprintf 3 +default which prints the entire string if the precision is unspecified). +.It +The conversion characters ``h'', ``l'', ``n'', ``p'' and ``q'' are +not supported. +.It +The single character escape sequences +described in the C standard are supported: +.Bd -ragged -offset indent -compact +.Bl -column +.It NUL \e0 +.It \ea +.It \eb +.It \ef +.It \en +.It \er +.It \et +.It \ev +.El +.Ed +.El +.Pp +Hexdump also supports the the following additional conversion strings: +.Bl -tag -width Fl +.It Cm \&_a Ns Op Cm dox +Display the input offset, cumulative across input files, of the +next byte to be displayed. +The appended characters +.Cm d , +.Cm o , +and +.Cm x +specify the display base +as decimal, octal or hexadecimal respectively. +.It Cm \&_A Ns Op Cm dox +Identical to the +.Cm \&_a +conversion string except that it is only performed +once, when all of the input data has been processed. +.It Cm \&_c +Output characters in the default character set. +Nonprinting characters are displayed in three character, zero-padded +octal, except for those representable by standard escape notation +(see above), +which are displayed as two character strings. +.It Cm _p +Output characters in the default character set. +Nonprinting characters are displayed as a single +.Dq Cm \&. . +.It Cm _u +Output US ASCII characters, with the exception that control characters are +displayed using the following, lower-case, names. +Characters greater than 0xff, hexadecimal, are displayed as hexadecimal +strings. +.Bl -column \&000_nu \&001_so \&002_st \&003_et \&004_eo +.It \&000\ nul\t001\ soh\t002\ stx\t003\ etx\t004\ eot\t005\ enq +.It \&006\ ack\t007\ bel\t008\ bs\t009\ ht\t00A\ lf\t00B\ vt +.It \&00C\ ff\t00D\ cr\t00E\ so\t00F\ si\t010\ dle\t011\ dc1 +.It \&012\ dc2\t013\ dc3\t014\ dc4\t015\ nak\t016\ syn\t017\ etb +.It \&018\ can\t019\ em\t01A\ sub\t01B\ esc\t01C\ fs\t01D\ gs +.It \&01E\ rs\t01F\ us\t0FF\ del +.El +.El +.Pp +The default and supported byte counts for the conversion characters +are as follows: +.Bl -tag -width "Xc,_Xc,_Xc,_Xc,_Xc,_Xc" -offset indent +.It Li \&%_c , \&%_p , \&%_u , \&%c +One byte counts only. +.It Xo +.Li \&%d , \&%i , \&%o , +.Li \&%u , \&%X , \&%x +.Xc +Four byte default, one, two and four byte counts supported. +.It Xo +.Li \&%E , \&%e , \&%f , +.Li \&%G , \&%g +.Xc +Eight byte default, four byte counts supported. +.El +.Pp +The amount of data interpreted by each format string is the sum of the +data required by each format unit, which is the iteration count times the +byte count, or the iteration count times the number of bytes required by +the format if the byte count is not specified. +.Pp +The input is manipulated in ``blocks'', where a block is defined as the +largest amount of data specified by any format string. +Format strings interpreting less than an input block's worth of data, +whose last format unit both interprets some number of bytes and does +not have a specified iteration count, have the iteration count +incremented until the entire input block has been processed or there +is not enough data remaining in the block to satisfy the format string. +.Pp +If, either as a result of user specification or hexdump modifying +the iteration count as described above, an iteration count is +greater than one, no trailing whitespace characters are output +during the last iteration. +.Pp +It is an error to specify a byte count as well as multiple conversion +characters or strings unless all but one of the conversion characters +or strings is +.Cm \&_a +or +.Cm \&_A . +.Pp +If, as a result of the specification of the +.Fl n +option or end-of-file being reached, input data only partially +satisfies a format string, the input block is zero-padded sufficiently +to display all available data (i.e. any format units overlapping the +end of data will display some number of the zero bytes). +.Pp +Further output by such format strings is replaced by an equivalent +number of spaces. +An equivalent number of spaces is defined as the number of spaces +output by an +.Cm s +conversion character with the same field width +and precision as the original conversion character or conversion +string but with any +.Dq Li \&+ , +.Dq \&\ \& , +.Dq Li \&# +conversion flag characters +removed, and referencing a NULL string. +.Pp +If no format strings are specified, the default display is equivalent +to specifying the +.Fl x +option. +.Pp +.Nm hexdump +exits 0 on success and >0 if an error occurred. +.Sh EXAMPLES +Display the input in perusal format: +.Bd -literal -offset indent +"%06.6_ao " 12/1 "%3_u " +"\et\et" "%_p " +"\en" +.Ed +.Pp +Implement the \-x option: +.Bd -literal -offset indent +"%07.7_Ax\en" +"%07.7_ax " 8/2 "%04x " "\en" +.Ed +.Sh SEE ALSO +.Xr adb 1 diff --git a/usr.bin/hexdump/hexdump.c b/usr.bin/hexdump/hexdump.c new file mode 100644 index 0000000..fec0b10 --- /dev/null +++ b/usr.bin/hexdump/hexdump.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)hexdump.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include "hexdump.h" + +FS *fshead; /* head of format strings */ +int blocksize; /* data block size */ +int exitval; /* final exit value */ +int length = -1; /* max bytes to read */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register FS *tfs; + char *p; + + if (!(p = rindex(argv[0], 'o')) || strcmp(p, "od")) + newsyntax(argc, &argv); + else + oldsyntax(argc, &argv); + + /* figure out the data block size */ + for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) { + tfs->bcnt = size(tfs); + if (blocksize < tfs->bcnt) + blocksize = tfs->bcnt; + } + /* rewrite the rules, do syntax checking */ + for (tfs = fshead; tfs; tfs = tfs->nextfs) + rewrite(tfs); + + (void)next(argv); + display(); + exit(exitval); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "hexdump: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/hexdump/hexdump.h b/usr.bin/hexdump/hexdump.h new file mode 100644 index 0000000..82ec51d --- /dev/null +++ b/usr.bin/hexdump/hexdump.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)hexdump.h 8.1 (Berkeley) 6/6/93 + */ + +typedef struct _pr { + struct _pr *nextpr; /* next print unit */ +#define F_ADDRESS 0x001 /* print offset */ +#define F_BPAD 0x002 /* blank pad */ +#define F_C 0x004 /* %_c */ +#define F_CHAR 0x008 /* %c */ +#define F_DBL 0x010 /* %[EefGf] */ +#define F_INT 0x020 /* %[di] */ +#define F_P 0x040 /* %_p */ +#define F_STR 0x080 /* %s */ +#define F_U 0x100 /* %_u */ +#define F_UINT 0x200 /* %[ouXx] */ +#define F_TEXT 0x400 /* no conversions */ + u_int flags; /* flag values */ + int bcnt; /* byte count */ + char *cchar; /* conversion character */ + char *fmt; /* printf format */ + char *nospace; /* no whitespace version */ +} PR; + +typedef struct _fu { + struct _fu *nextfu; /* next format unit */ + struct _pr *nextpr; /* next print unit */ +#define F_IGNORE 0x01 /* %_A */ +#define F_SETREP 0x02 /* rep count set, not default */ + u_int flags; /* flag values */ + int reps; /* repetition count */ + int bcnt; /* byte count */ + char *fmt; /* format string */ +} FU; + +typedef struct _fs { /* format strings */ + struct _fs *nextfs; /* linked list of format strings */ + struct _fu *nextfu; /* linked list of format units */ + int bcnt; +} FS; + +extern FS *fshead; /* head of format strings list */ +extern int blocksize; /* data block size */ +enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ + +void add __P((char *)); +void addfile __P((char *)); +void badcnt __P((char *)); +void badconv __P((char *)); +void badfmt __P((char *)); +void badsfmt __P((void)); +void bpad __P((PR *)); +void conv_c __P((PR *, u_char *)); +void conv_u __P((PR *, u_char *)); +void display __P((void)); +void doskip __P((char *, int)); +void err __P((const char *, ...)); +void *emalloc __P((int)); +void escape __P((char *)); +u_char *get __P((void)); +void newsyntax __P((int, char ***)); +int next __P((char **)); +void nomem __P((void)); +void oldsyntax __P((int, char ***)); +void rewrite __P((FS *)); +int size __P((FS *)); +void usage __P((void)); diff --git a/usr.bin/hexdump/hexsyntax.c b/usr.bin/hexdump/hexsyntax.c new file mode 100644 index 0000000..68abbe6 --- /dev/null +++ b/usr.bin/hexdump/hexsyntax.c @@ -0,0 +1,127 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)hexsyntax.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include "hexdump.h" + +off_t skip; /* bytes to skip */ + +void +newsyntax(argc, argvp) + int argc; + char ***argvp; +{ + extern enum _vflag vflag; + extern FS *fshead; + extern int length; + int ch; + char *p, **argv; + + argv = *argvp; + while ((ch = getopt(argc, argv, "bcde:f:n:os:vx")) != EOF) + switch (ch) { + case 'b': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\""); + break; + case 'c': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\""); + break; + case 'd': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\""); + break; + case 'e': + add(optarg); + break; + case 'f': + addfile(optarg); + break; + case 'n': + if ((length = atoi(optarg)) < 0) + err("%s: bad length value", optarg); + break; + case 'o': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\""); + break; + case 's': + if ((skip = strtol(optarg, &p, 0)) < 0) + err("%s: bad skip value", optarg); + switch(*p) { + case 'b': + skip *= 512; + break; + case 'k': + skip *= 1024; + break; + case 'm': + skip *= 1048576; + break; + } + break; + case 'v': + vflag = ALL; + break; + case 'x': + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\""); + break; + case '?': + usage(); + } + + if (!fshead) { + add("\"%07.7_Ax\n\""); + add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); + } + + *argvp += optind; +} + +void +usage() +{ + (void)fprintf(stderr, +"hexdump: [-bcdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/hexdump/od.1 b/usr.bin/hexdump/od.1 new file mode 100644 index 0000000..dab6da7 --- /dev/null +++ b/usr.bin/hexdump/od.1 @@ -0,0 +1,76 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)od.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd %Q +.Os +.Dt OD 1 +.Sh NAME +.Nm od +.Nd octal, decimal, hex, ascii dump +.Sh SYNOPSIS +.Nm od +.Op Fl aBbcDdeFfHhIiLlOovXx +.Sm off +.Oo +.Op Cm \&+ +.Li offset +.Op Cm \&. +.Op Cm Bb +.Oc +.Ar file +.Sh DESCRIPTION +.Nm Od +has been deprecated in favor of +.Xr hexdump 1 . +.Pp +.Xr Hexdump , +if called as +.Nm od , +provides compatibility for the options listed above. +.Pp +It does not provide compatibility for the +.Fl s +option (see +.Xr strings 1 ) +or the +.Fl P , +.Fl p , +or +.Fl w +options, nor is compatibility provided for the ``label'' component +of the offset syntax. +.Sh SEE ALSO +.Xr hexdump 1 , +.Xr strings 1 +.Sh BUGS +Quite a few. diff --git a/usr.bin/hexdump/odsyntax.c b/usr.bin/hexdump/odsyntax.c new file mode 100644 index 0000000..1a4011f --- /dev/null +++ b/usr.bin/hexdump/odsyntax.c @@ -0,0 +1,263 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)odsyntax.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include "hexdump.h" + +int deprecated; + +static void odoffset __P((int, char ***)); +static void odprecede __P((void)); + +void +oldsyntax(argc, argvp) + int argc; + char ***argvp; +{ + extern enum _vflag vflag; + extern FS *fshead; + int ch; + char **argv; + + deprecated = 1; + argv = *argvp; + while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != EOF) + switch (ch) { + case 'a': + odprecede(); + add("16/1 \"%3_u \" \"\\n\""); + break; + case 'B': + case 'o': + odprecede(); + add("8/2 \" %06o \" \"\\n\""); + break; + case 'b': + odprecede(); + add("16/1 \"%03o \" \"\\n\""); + break; + case 'c': + odprecede(); + add("16/1 \"%3_c \" \"\\n\""); + break; + case 'd': + odprecede(); + add("8/2 \" %05u \" \"\\n\""); + break; + case 'D': + odprecede(); + add("4/4 \" %010u \" \"\\n\""); + break; + case 'e': /* undocumented in od */ + case 'F': + odprecede(); + add("2/8 \" %21.14e \" \"\\n\""); + break; + + case 'f': + odprecede(); + add("4/4 \" %14.7e \" \"\\n\""); + break; + case 'H': + case 'X': + odprecede(); + add("4/4 \" %08x \" \"\\n\""); + break; + case 'h': + case 'x': + odprecede(); + add("8/2 \" %04x \" \"\\n\""); + break; + case 'I': + case 'L': + case 'l': + odprecede(); + add("4/4 \" %11d \" \"\\n\""); + break; + case 'i': + odprecede(); + add("8/2 \" %6d \" \"\\n\""); + break; + case 'O': + odprecede(); + add("4/4 \" %011o \" \"\\n\""); + break; + case 'v': + vflag = ALL; + break; + case 'P': + case 'p': + case 's': + case 'w': + case '?': + default: + (void)fprintf(stderr, + "od: od(1) has been deprecated for hexdump(1).\n"); + if (ch != '?') + (void)fprintf(stderr, +"od: hexdump(1) compatibility doesn't support the -%c option%s\n", + ch, ch == 's' ? "; see strings(1)." : "."); + usage(); + } + + if (!fshead) { + add("\"%07.7_Ao\n\""); + add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\""); + } + + argc -= optind; + *argvp += optind; + + if (argc) + odoffset(argc, argvp); +} + +static void +odoffset(argc, argvp) + int argc; + char ***argvp; +{ + extern off_t skip; + register char *num, *p; + int base; + char *end; + + /* + * The offset syntax of od(1) was genuinely bizarre. First, if + * it started with a plus it had to be an offset. Otherwise, if + * there were at least two arguments, a number or lower-case 'x' + * followed by a number makes it an offset. By default it was + * octal; if it started with 'x' or '0x' it was hex. If it ended + * in a '.', it was decimal. If a 'b' or 'B' was appended, it + * multiplied the number by 512 or 1024 byte units. There was + * no way to assign a block count to a hex offset. + * + * We assume it's a file if the offset is bad. + */ + p = argc == 1 ? (*argvp)[0] : (*argvp)[1]; + + if (*p != '+' && (argc < 2 || + (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1]))))) + return; + + base = 0; + /* + * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and + * set base. + */ + if (p[0] == '+') + ++p; + if (p[0] == 'x' && isxdigit(p[1])) { + ++p; + base = 16; + } else if (p[0] == '0' && p[1] == 'x') { + p += 2; + base = 16; + } + + /* skip over the number */ + if (base == 16) + for (num = p; isxdigit(*p); ++p); + else + for (num = p; isdigit(*p); ++p); + + /* check for no number */ + if (num == p) + return; + + /* if terminates with a '.', base is decimal */ + if (*p == '.') { + if (base) + return; + base = 10; + } + + skip = strtol(num, &end, base ? base : 8); + + /* if end isn't the same as p, we got a non-octal digit */ + if (end != p) { + skip = 0; + return; + } + + if (*p) + if (*p == 'B') { + skip *= 1024; + ++p; + } else if (*p == 'b') { + skip *= 512; + ++p; + } + + if (*p) { + skip = 0; + return; + } + + /* + * If the offset uses a non-octal base, the base of the offset + * is changed as well. This isn't pretty, but it's easy. + */ +#define TYPE_OFFSET 7 + if (base == 16) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'x'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x'; + } else if (base == 10) { + fshead->nextfu->fmt[TYPE_OFFSET] = 'd'; + fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd'; + } + + /* Terminate file list. */ + (*argvp)[1] = NULL; +} + +static void +odprecede() +{ + static int first = 1; + + if (first) { + first = 0; + add("\"%07.7_Ao\n\""); + add("\"%07.7_ao \""); + } else + add("\" \""); +} diff --git a/usr.bin/hexdump/parse.c b/usr.bin/hexdump/parse.c new file mode 100644 index 0000000..99c207a --- /dev/null +++ b/usr.bin/hexdump/parse.c @@ -0,0 +1,507 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include "hexdump.h" + +FU *endfu; /* format at end-of-data */ + +void +addfile(name) + char *name; +{ + register char *p; + FILE *fp; + int ch; + char buf[2048 + 1]; + + if ((fp = fopen(name, "r")) == NULL) + err("%s: %s\n", name, strerror(errno)); + while (fgets(buf, sizeof(buf), fp)) { + if (!(p = index(buf, '\n'))) { + (void)fprintf(stderr, "hexdump: line too long.\n"); + while ((ch = getchar()) != '\n' && ch != EOF); + continue; + } + *p = '\0'; + for (p = buf; *p && isspace(*p); ++p); + if (!*p || *p == '#') + continue; + add(p); + } + (void)fclose(fp); +} + +void +add(fmt) + char *fmt; +{ + register char *p; + static FS **nextfs; + FS *tfs; + FU *tfu, **nextfu; + char *savep; + + /* start new linked list of format units */ + tfs = emalloc(sizeof(FS)); + if (!fshead) + fshead = tfs; + else + *nextfs = tfs; + nextfs = &tfs->nextfs; + nextfu = &tfs->nextfu; + + /* take the format string and break it up into format units */ + for (p = fmt;;) { + /* skip leading white space */ + for (; isspace(*p); ++p); + if (!*p) + break; + + /* allocate a new format unit and link it in */ + tfu = emalloc(sizeof(FU)); + *nextfu = tfu; + nextfu = &tfu->nextfu; + tfu->reps = 1; + + /* if leading digit, repetition count */ + if (isdigit(*p)) { + for (savep = p; isdigit(*p); ++p); + if (!isspace(*p) && *p != '/') + badfmt(fmt); + /* may overwrite either white space or slash */ + tfu->reps = atoi(savep); + tfu->flags = F_SETREP; + /* skip trailing white space */ + for (++p; isspace(*p); ++p); + } + + /* skip slash and trailing white space */ + if (*p == '/') + while (isspace(*++p)); + + /* byte count */ + if (isdigit(*p)) { + for (savep = p; isdigit(*p); ++p); + if (!isspace(*p)) + badfmt(fmt); + tfu->bcnt = atoi(savep); + /* skip trailing white space */ + for (++p; isspace(*p); ++p); + } + + /* format */ + if (*p != '"') + badfmt(fmt); + for (savep = ++p; *p != '"';) + if (*p++ == 0) + badfmt(fmt); + if (!(tfu->fmt = malloc(p - savep + 1))) + nomem(); + (void) strncpy(tfu->fmt, savep, p - savep); + tfu->fmt[p - savep] = '\0'; + escape(tfu->fmt); + p++; + } +} + +static char *spec = ".#-+ 0123456789"; + +int +size(fs) + FS *fs; +{ + register FU *fu; + register int bcnt, cursize; + register char *fmt; + int prec; + + /* figure out the data block size needed for each format unit */ + for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { + if (fu->bcnt) { + cursize += fu->bcnt * fu->reps; + continue; + } + for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { + if (*fmt != '%') + continue; + /* + * skip any special chars -- save precision in + * case it's a %s format. + */ + while (index(spec + 1, *++fmt)); + if (*fmt == '.' && isdigit(*++fmt)) { + prec = atoi(fmt); + while (isdigit(*++fmt)); + } + switch(*fmt) { + case 'c': + bcnt += 1; + break; + case 'd': case 'i': case 'o': case 'u': + case 'x': case 'X': + bcnt += 4; + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + bcnt += 8; + break; + case 's': + bcnt += prec; + break; + case '_': + switch(*++fmt) { + case 'c': case 'p': case 'u': + bcnt += 1; + break; + } + } + } + cursize += bcnt * fu->reps; + } + return (cursize); +} + +void +rewrite(fs) + FS *fs; +{ + enum { NOTOKAY, USEBCNT, USEPREC } sokay; + register PR *pr, **nextpr; + register FU *fu; + register char *p1, *p2; + char savech, *fmtp, cs[3]; + int nconv, prec; + + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + /* + * Break each format unit into print units; each conversion + * character gets its own. + */ + for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + pr = emalloc(sizeof(PR)); + if (!fu->nextpr) + fu->nextpr = pr; + else + *nextpr = pr; + + /* Skip preceding text and up to the next % sign. */ + for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); + + /* Only text in the string. */ + if (!*p1) { + pr->fmt = fmtp; + pr->flags = F_TEXT; + break; + } + + /* + * Get precision for %s -- if have a byte count, don't + * need it. + */ + if (fu->bcnt) { + sokay = USEBCNT; + /* Skip to conversion character. */ + for (++p1; index(spec, *p1); ++p1); + } else { + /* Skip any special chars, field width. */ + while (index(spec + 1, *++p1)); + if (*p1 == '.' && isdigit(*++p1)) { + sokay = USEPREC; + prec = atoi(p1); + while (isdigit(*++p1)); + } else + sokay = NOTOKAY; + } + + p2 = p1 + 1; /* Set end pointer. */ + cs[0] = *p1; /* Set conversion string. */ + cs[1] = '\0'; + + /* + * Figure out the byte count for each conversion; + * rewrite the format as necessary, set up blank- + * padding for end of data. + */ + switch(cs[0]) { + case 'c': + pr->flags = F_CHAR; + switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'd': case 'i': + pr->flags = F_INT; + goto isint; + case 'o': case 'u': case 'x': case 'X': + pr->flags = F_UINT; +isint: cs[2] = '\0'; + cs[1] = cs[0]; + cs[0] = 'q'; + switch(fu->bcnt) { + case 0: case 4: + pr->bcnt = 4; + break; + case 1: + pr->bcnt = 1; + break; + case 2: + pr->bcnt = 2; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + pr->flags = F_DBL; + switch(fu->bcnt) { + case 0: case 8: + pr->bcnt = 8; + break; + case 4: + pr->bcnt = 4; + break; + default: + p1[1] = '\0'; + badcnt(p1); + } + break; + case 's': + pr->flags = F_STR; + switch(sokay) { + case NOTOKAY: + badsfmt(); + case USEBCNT: + pr->bcnt = fu->bcnt; + break; + case USEPREC: + pr->bcnt = prec; + break; + } + break; + case '_': + ++p2; + switch(p1[1]) { + case 'A': + endfu = fu; + fu->flags |= F_IGNORE; + /* FALLTHROUGH */ + case 'a': + pr->flags = F_ADDRESS; + ++p2; + switch(p1[2]) { + case 'd': case 'o': case'x': + cs[0] = 'q'; + cs[1] = p1[2]; + cs[2] = '\0'; + break; + default: + p1[3] = '\0'; + badconv(p1); + } + break; + case 'c': + pr->flags = F_C; + /* cs[0] = 'c'; set in conv_c */ + goto isint2; + case 'p': + pr->flags = F_P; + cs[0] = 'c'; + goto isint2; + case 'u': + pr->flags = F_U; + /* cs[0] = 'c'; set in conv_u */ +isint2: switch(fu->bcnt) { + case 0: case 1: + pr->bcnt = 1; + break; + default: + p1[2] = '\0'; + badcnt(p1); + } + break; + default: + p1[2] = '\0'; + badconv(p1); + } + break; + default: + p1[1] = '\0'; + badconv(p1); + } + + /* + * Copy to PR format string, set conversion character + * pointer, update original. + */ + savech = *p2; + p1[0] = '\0'; + pr->fmt = emalloc(strlen(fmtp) + 2); + (void)strcpy(pr->fmt, fmtp); + (void)strcat(pr->fmt, cs); + *p2 = savech; + pr->cchar = pr->fmt + (p1 - fmtp); + fmtp = p2; + + /* Only one conversion character if byte count. */ + if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) + err("byte count with multiple conversion characters"); + } + /* + * If format unit byte count not specified, figure it out + * so can adjust rep count later. + */ + if (!fu->bcnt) + for (pr = fu->nextpr; pr; pr = pr->nextpr) + fu->bcnt += pr->bcnt; + } + /* + * If the format string interprets any data at all, and it's + * not the same as the blocksize, and its last format unit + * interprets any data at all, and has no iteration count, + * repeat it as necessary. + * + * If, rep count is greater than 1, no trailing whitespace + * gets output from the last iteration of the format unit. + */ + for (fu = fs->nextfu;; fu = fu->nextfu) { + if (!fu->nextfu && fs->bcnt < blocksize && + !(fu->flags&F_SETREP) && fu->bcnt) + fu->reps += (blocksize - fs->bcnt) / fu->bcnt; + if (fu->reps > 1) { + for (pr = fu->nextpr;; pr = pr->nextpr) + if (!pr->nextpr) + break; + for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) + p2 = isspace(*p1) ? p1 : NULL; + if (p2) + pr->nospace = p2; + } + if (!fu->nextfu) + break; + } +#ifdef DEBUG + for (fu = fs->nextfu; fu; fu = fu->nextfu) { + (void)printf("fmt:"); + for (pr = fu->nextpr; pr; pr = pr->nextpr) + (void)printf(" {%s}", pr->fmt); + (void)printf("\n"); + } +#endif +} + +void +escape(p1) + register char *p1; +{ + register char *p2; + + /* alphabetic escape sequences have to be done in place */ + for (p2 = p1;; ++p1, ++p2) { + if (!*p1) { + *p2 = *p1; + break; + } + if (*p1 == '\\') + switch(*++p1) { + case 'a': + /* *p2 = '\a'; */ + *p2 = '\007'; + break; + case 'b': + *p2 = '\b'; + break; + case 'f': + *p2 = '\f'; + break; + case 'n': + *p2 = '\n'; + break; + case 'r': + *p2 = '\r'; + break; + case 't': + *p2 = '\t'; + break; + case 'v': + *p2 = '\v'; + break; + default: + *p2 = *p1; + break; + } + } +} + +void +badcnt(s) + char *s; +{ + err("%s: bad byte count", s); +} + +void +badsfmt() +{ + err("%%s: requires a precision or a byte count\n"); +} + +void +badfmt(fmt) + char *fmt; +{ + err("\"%s\": bad format\n", fmt); +} + +void +badconv(ch) + char *ch; +{ + err("%%%s: bad conversion character\n", ch); +} diff --git a/usr.bin/id/Makefile b/usr.bin/id/Makefile new file mode 100644 index 0000000..44eaa4a --- /dev/null +++ b/usr.bin/id/Makefile @@ -0,0 +1,14 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= id +MAN1= id.0 groups.0 whoami.0 + +afterinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/groups.sh ${DESTDIR}/usr/bin/groups + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/whoami.sh ${DESTDIR}/usr/bin/whoami + ${MINSTALL} groups.0 ${DESTDIR}${MANDIR}1/groups.0 + ${MINSTALL} whoami.0 ${DESTDIR}${MANDIR}1/whoami.0 + +.include diff --git a/usr.bin/id/groups.1 b/usr.bin/id/groups.1 new file mode 100644 index 0000000..35653dc --- /dev/null +++ b/usr.bin/id/groups.1 @@ -0,0 +1,63 @@ +.\" 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. +.\" +.\" @(#)groups.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 6, 1993" +.Dt GROUPS 1 +.UC +.Sh NAME +.Nm groups +.Nd show group memberships +.Sh SYNOPSIS +.Nm groups +.Op Ar user +.Sh DESCRIPTION +The +.Nm groups +utility has been obsoleted by the +.Xr id 1 +utility, and is equivalent to +.Dq Nm id Fl Gn Op Ar user . +The command +.Dq Nm id Fl p +is suggested for normal interactive use. +.Pp +The +.Nm groups +utility displays the groups to which you (or the optionally specified user) +belong. +.Pp +The +.Nm groups +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr id 1 diff --git a/usr.bin/id/groups.sh b/usr.bin/id/groups.sh new file mode 100644 index 0000000..e29ed90 --- /dev/null +++ b/usr.bin/id/groups.sh @@ -0,0 +1,37 @@ +#!/bin/sh - +# +# 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. +# +# @(#)groups.sh 8.1 (Berkeley) 6/6/93 +# + +id -Gn $* diff --git a/usr.bin/id/id.1 b/usr.bin/id/id.1 new file mode 100644 index 0000000..99010fc --- /dev/null +++ b/usr.bin/id/id.1 @@ -0,0 +1,139 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)id.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 6, 1993" +.Dt ID 1 +.Os BSD 4.4 +.Sh NAME +.Nm id +.Nd return user identity +.Sh SYNOPSIS +.Nm id +.Op Ar user +.Nm id +.Fl G Op Fl n +.Op Ar user +.Nm id +.Fl g Op Fl nr +.Op Ar user +.Nm id +.Fl p +.Nm id +.Fl u Op Fl nr +.Op Ar user +.Sh DESCRIPTION +The +.Nm id +utility displays the user and group names and numeric IDs, of the +calling process, to the standard output. +If the real and effective IDs are different, both are displayed, +otherwise only the real ID is displayed. +.Pp +If a +.Ar user +(login name or user ID) +is specified, the user and group IDs of that user are displayed. +In this case, the real and effective IDs are assumed to be the same. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl G +Display the different group IDs (effective, real and supplementary) +as white-space separated numbers, in no particular order. +.It Fl g +Display the effective group ID as a number. +.It Fl n +Display the name of the user or group ID for the +.Fl G , +.Fl g +and +.Fl u +options instead of the number. +If any of the ID numbers cannot be mapped into names, the number will be +displayed as usual. +.It Fl p +Make the output human-readable. +If the user name returned by +.Xr getlogin 2 +is different from the login name referenced by the user ID, the name +returned by +.Xr getlogin 2 +is displayed, preceded by the keyword ``login''. +The user ID as a name is displayed, preceded by the keyword ``uid''. +If the effective user ID is different from the real user ID, the real user +ID is displayed as a name, preceded by the keyword ``euid''. +If the effective group ID is different from the real group ID, the real group +ID is displayed as a name, preceded by the keyword ``rgid''. +The list of groups to which the user belongs is then displayed as names, +preceded by the keyword ``groups''. +Each display is on a separate line. +.It Fl r +Display the real ID for the +.Fl g +and +.Fl u +options instead of the effective ID. +.It Fl u +Display the effective user ID as a number. +.El +.Pp +The +.Nm id +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr who 1 +.Sh STANDARDS +The +.Nm id +function is expected to conform to +.St -p1003.2 . +.Sh HISTORY +The +historic +.Xr groups 1 +command is equivalent to +.Dq Nm id Fl Gn Op Ar user . +.Pp +The +historic +.Xr whoami 1 +command is equivalent to +.Dq Nm id Fl un . +.Pp +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/id/id.c b/usr.bin/id/id.c new file mode 100644 index 0000000..a2d6ea6 --- /dev/null +++ b/usr.bin/id/id.c @@ -0,0 +1,351 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)id.c 8.2 (Berkeley) 2/16/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +void current __P((void)); +void err __P((const char *, ...)); +void pretty __P((struct passwd *)); +void group __P((struct passwd *, int)); +void usage __P((void)); +void user __P((struct passwd *)); +struct passwd * + who __P((char *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct group *gr; + struct passwd *pw; + int Gflag, ch, gflag, id, nflag, pflag, rflag, uflag; + + Gflag = gflag = nflag = pflag = rflag = uflag = 0; + while ((ch = getopt(argc, argv, "Ggnpru")) != EOF) + switch(ch) { + case 'G': + Gflag = 1; + break; + case 'g': + gflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'p': + pflag = 1; + break; + case 'r': + rflag = 1; + break; + case 'u': + uflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch(Gflag + gflag + pflag + uflag) { + case 1: + break; + case 0: + if (!nflag && !rflag) + break; + /* FALLTHROUGH */ + default: + usage(); + } + + pw = *argv ? who(*argv) : NULL; + + if (gflag) { + id = pw ? pw->pw_gid : rflag ? getgid() : getegid(); + if (nflag && (gr = getgrgid(id))) + (void)printf("%s\n", gr->gr_name); + else + (void)printf("%u\n", id); + exit(0); + } + + if (uflag) { + id = pw ? pw->pw_uid : rflag ? getuid() : geteuid(); + if (nflag && (pw = getpwuid(id))) + (void)printf("%s\n", pw->pw_name); + else + (void)printf("%u\n", id); + exit(0); + } + + if (Gflag) { + group(pw, nflag); + exit(0); + } + + if (pflag) { + pretty(pw); + exit(0); + } + + if (pw) + user(pw); + else + current(); + exit(0); +} + +void +pretty(pw) + struct passwd *pw; +{ + struct group *gr; + u_int eid, rid; + char *login; + + if (pw) { + (void)printf("uid\t%s\n", pw->pw_name); + (void)printf("groups\t"); + group(pw, 1); + } else { + if ((login = getlogin()) == NULL) + err("getlogin: %s", strerror(errno)); + + pw = getpwuid(rid = getuid()); + if (pw == NULL || strcmp(login, pw->pw_name)) + (void)printf("login\t%s\n", login); + if (pw) + (void)printf("uid\t%s\n", pw->pw_name); + else + (void)printf("uid\t%u\n", rid); + + if ((eid = geteuid()) != rid) + if (pw = getpwuid(eid)) + (void)printf("euid\t%s", pw->pw_name); + else + (void)printf("euid\t%u", eid); + if ((rid = getgid()) != (eid = getegid())) + if (gr = getgrgid(rid)) + (void)printf("rgid\t%s\n", gr->gr_name); + else + (void)printf("rgid\t%u\n", rid); + (void)printf("groups\t"); + group(NULL, 1); + } +} + +void +current() +{ + struct group *gr; + struct passwd *pw; + int cnt, id, eid, lastid, ngroups; + gid_t groups[NGROUPS]; + char *fmt; + + id = getuid(); + (void)printf("uid=%u", id); + if (pw = getpwuid(id)) + (void)printf("(%s)", pw->pw_name); + if ((eid = geteuid()) != id) { + (void)printf(" euid=%u", eid); + if (pw = getpwuid(eid)) + (void)printf("(%s)", pw->pw_name); + } + id = getgid(); + (void)printf(" gid=%u", id); + if (gr = getgrgid(id)) + (void)printf("(%s)", gr->gr_name); + if ((eid = getegid()) != id) { + (void)printf(" egid=%u", eid); + if (gr = getgrgid(eid)) + (void)printf("(%s)", gr->gr_name); + } + if (ngroups = getgroups(NGROUPS, groups)) { + for (fmt = " groups=%u", lastid = -1, cnt = 0; cnt < ngroups; + fmt = ", %u", lastid = id) { + id = groups[cnt++]; + if (lastid == id) + continue; + (void)printf(fmt, id); + if (gr = getgrgid(id)) + (void)printf("(%s)", gr->gr_name); + } + } + (void)printf("\n"); +} + +void +user(pw) + register struct passwd *pw; +{ + register struct group *gr; + register char *fmt, **p; + int cnt, id, lastid, ngroups, groups[NGROUPS + 1]; + + id = pw->pw_uid; + (void)printf("uid=%u(%s)", id, pw->pw_name); + (void)printf(" gid=%u", pw->pw_gid); + if (gr = getgrgid(id)) + (void)printf("(%s)", gr->gr_name); + ngroups = NGROUPS + 1; + (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); + fmt = " groups=%u"; + for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) { + if (lastid == (id = groups[cnt])) + continue; + (void)printf(fmt, id); + fmt = " %u"; + if (gr = getgrgid(id)) + (void)printf("(%s)", gr->gr_name); + lastid = id; + } + (void)printf("\n"); +} + +void +group(pw, nflag) + struct passwd *pw; + int nflag; +{ + struct group *gr; + int cnt, id, lastid, ngroups; + gid_t groups[NGROUPS + 1]; + char *fmt; + + if (pw) { + ngroups = NGROUPS + 1; + (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); + } else { + groups[0] = getgid(); + ngroups = getgroups(NGROUPS, groups + 1) + 1; + } + fmt = nflag ? "%s" : "%u"; + for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) { + if (lastid == (id = groups[cnt])) + continue; + if (nflag) { + if (gr = getgrgid(id)) + (void)printf(fmt, gr->gr_name); + else + (void)printf(*fmt == ' ' ? " %u" : "%u", + id); + fmt = " %s"; + } else { + (void)printf(fmt, id); + fmt = " %u"; + } + lastid = id; + } + (void)printf("\n"); +} + +struct passwd * +who(u) + char *u; +{ + struct passwd *pw; + long id; + char *ep; + + /* + * Translate user argument into a pw pointer. First, try to + * get it as specified. If that fails, try it as a number. + */ + if (pw = getpwnam(u)) + return(pw); + id = strtol(u, &ep, 10); + if (*u && !*ep && (pw = getpwuid(id))) + return(pw); + err("%s: No such user", u); + /* NOTREACHED */ +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "id: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} + +void +usage() +{ + (void)fprintf(stderr, "usage: id [user]\n"); + (void)fprintf(stderr, " id -G [-n] [user]\n"); + (void)fprintf(stderr, " id -g [-nr] [user]\n"); + (void)fprintf(stderr, " id -u [-nr] [user]\n"); + exit(1); +} diff --git a/usr.bin/id/whoami.1 b/usr.bin/id/whoami.1 new file mode 100644 index 0000000..7cf7b43 --- /dev/null +++ b/usr.bin/id/whoami.1 @@ -0,0 +1,61 @@ +.\" 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. +.\" +.\" @(#)whoami.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 6, 1993" +.Dt WHOAMI 1 +.UC +.Sh NAME +.Nm whoami +.Nd display effective user id +.Sh SYNOPSIS +.Nm whoami +.Sh DESCRIPTION +The +.Nm whoami +utility has been obsoleted by the +.Xr id 1 +utility, and is equivalent to +.Dq Nm id Fl un . +The command +.Dq Nm id Fl p +is suggested for normal interactive use. +.Pp +The +.Nm whoami +utility displays your effective user ID as a name. +.Pp +The +.Nm whoami +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr id 1 diff --git a/usr.bin/id/whoami.sh b/usr.bin/id/whoami.sh new file mode 100644 index 0000000..372b7da --- /dev/null +++ b/usr.bin/id/whoami.sh @@ -0,0 +1,37 @@ +#!/bin/sh - +# +# 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. +# +# @(#)whoami.sh 8.1 (Berkeley) 6/6/93 +# + +id -un diff --git a/usr.bin/indent/Makefile b/usr.bin/indent/Makefile new file mode 100644 index 0000000..8d9ff94 --- /dev/null +++ b/usr.bin/indent/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= indent +SRCS= indent.c io.c lexi.c parse.c pr_comment.c args.c + +.include diff --git a/usr.bin/indent/README b/usr.bin/indent/README new file mode 100644 index 0000000..618f1de --- /dev/null +++ b/usr.bin/indent/README @@ -0,0 +1,97 @@ +This is the C indenter, it originally came from the University of Illinois +via some distribution tape for PDP-11 Unix. It has subsequently been +hacked upon by James Gosling @ CMU. It isn't very pretty, and really needs +to be completely redone, but it is probably the nicest C pretty printer +around. + +Further additions to provide "Kernel Normal Form" were contributed +by the folks at Sun Microsystems. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +> From mnetor!yunexus!oz@uunet.UU.NET Wed Mar 9 15:30:55 1988 +> Date: Tue, 8 Mar 88 18:36:25 EST +> From: yunexus!oz@uunet.UU.NET (Ozan Yigit) +> To: bostic@okeeffe.berkeley.edu +> Cc: ccvaxa!willcox@uunet.UU.NET, jag@sun.com, rsalz@uunet.UU.NET +> In-Reply-To: Keith Bostic's message of Tue, 16 Feb 88 16:09:06 PST +> Subject: Re: Indent... + +Thank you for your response about indent. I was wrong in my original +observation (or mis-observation :-). UCB did keep the Illinois +copyright intact. + +The issue still is whether we can distribute indent, and if we can, which +version. David Willcox (the author) states that: + +| Several people have asked me on what basis I claim that indent is in +| the public domain. I knew I would be sorry I made that posting. +| +| Some history. Way back in 1976, the project I worked on at the +| University of Illinois Center for Advanced Computation had a huge +| battle about how to format C code. After about a week of fighting, I +| got disgusted and wrote a program, which I called indent, to reformat C +| code. It had a bunch of different options that would let you format +| the output the way you liked. In particular, all of the different +| formats being championed were supported. +| +| It was my first big C program. It was ugly. It wasn't designed, it +| just sort of grew. But it pretty much worked, and it stopped most of +| the fighting. +| +| As a matter of form, I included a University of Illinois Copyright +| notice. However, my understanding was that, since the work was done +| on an ARPA contract, it was in the public domain. +| +| Time passed. Some years later, indent showed up on one of the early +| emacs distributions. +| +| Later still, someone from UC Berlekey called the UofI and asked if +| indent was in the public domain. They wanted to include it in their +| UNIX distributions, along with the emacs stuff. I was no longer at the +| UofI, but Rob Kolstad, who was, asked me about it. I told him I didn't +| care if they used it, and since then it has been on the BSD distributions. +| +| Somewhere along the way, several other unnamed people have had their +| hands in it. It was converted to understand version 7 C. (The +| original was version 6.) It was converted from its original filter +| interface to its current "blow away the user's file" interface. +| The $HOME/.indent.pro file parsing was added. Some more formatting +| options were added. +| +| The source I have right now has two copyright notices. One is the +| original from the UofI. One is from Berkeley. +| +| I am not a lawyer, and I certainly do not understand copyright law. As +| far as I am concerned, the bulk of this program, everything covered by +| the UofI copyright, is in the public domain, and worth every penny. +| Berkeley's copyright probably should only cover their changes, and I +| don't know their feelings about sending it out. + +In any case, there appears to be noone at UofI to clarify/and change +that copyright, but I am confident (based on the statements of its +author) that the code, as it stands with its copyright, is +distributable, and will not cause any legal problems. + +Hence, the issue reduces to *which* one to distribute through +comp.sources.unix. I would suggest that with the permission of you +folks (given that you have parts copyrighted), we distribute the 4.3 +version of indent, which appears to be the most up-to-date version. I +happen to have just about every known version of indent, including the +very original submission from the author to a unix tape, later the +G-Emacs version, any 4.n version, sun version and the Unipress +version. I still think we should not have to "go-back-in-time" and +re-do all the work you people have done. + +I hope to hear from you as to what you think about this. You may of +course send 4.3 version to the moderator directly, or you can let me +know of your permission, and I will send the sources, or you can let +me know that 4.3 version is off-limits, in which case we would probably +have to revert to an older version. One way or another, I hope to get +a version of indent to comp.sources.unix. + +regards.. oz + +cc: ccvaxa!willcox + sun.com!jar + uunet!rsalz + diff --git a/usr.bin/indent/args.c b/usr.bin/indent/args.c new file mode 100644 index 0000000..e62f038 --- /dev/null +++ b/usr.bin/indent/args.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)args.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Argument scanning and profile reading code. Default parameters are set + * here as well. + */ + +#include +#include +#include +#include +#include "indent_globs.h" + +/* profile types */ +#define PRO_SPECIAL 1 /* special case */ +#define PRO_BOOL 2 /* boolean */ +#define PRO_INT 3 /* integer */ +#define PRO_FONT 4 /* troff font */ + +/* profile specials for booleans */ +#define ON 1 /* turn it on */ +#define OFF 0 /* turn it off */ + +/* profile specials for specials */ +#define IGN 1 /* ignore it */ +#define CLI 2 /* case label indent (float) */ +#define STDIN 3 /* use stdin */ +#define KEY 4 /* type (keyword) */ + +char *option_source = "?"; + +/* + * N.B.: because of the way the table here is scanned, options whose names are + * substrings of other options must occur later; that is, with -lp vs -l, -lp + * must be first. Also, while (most) booleans occur more than once, the last + * default value is the one actually assigned. + */ +struct pro { + char *p_name; /* name, eg -bl, -cli */ + int p_type; /* type (int, bool, special) */ + int p_default; /* the default value (if int) */ + int p_special; /* depends on type */ + int *p_obj; /* the associated variable */ +} pro[] = { + + "T", PRO_SPECIAL, 0, KEY, 0, + "bacc", PRO_BOOL, false, ON, &blanklines_around_conditional_compilation, + "badp", PRO_BOOL, false, ON, &blanklines_after_declarations_at_proctop, + "bad", PRO_BOOL, false, ON, &blanklines_after_declarations, + "bap", PRO_BOOL, false, ON, &blanklines_after_procs, + "bbb", PRO_BOOL, false, ON, &blanklines_before_blockcomments, + "bc", PRO_BOOL, true, OFF, &ps.leave_comma, + "bl", PRO_BOOL, true, OFF, &btype_2, + "br", PRO_BOOL, true, ON, &btype_2, + "bs", PRO_BOOL, false, ON, &Bill_Shannon, + "cdb", PRO_BOOL, true, ON, &comment_delimiter_on_blankline, + "cd", PRO_INT, 0, 0, &ps.decl_com_ind, + "ce", PRO_BOOL, true, ON, &cuddle_else, + "ci", PRO_INT, 0, 0, &continuation_indent, + "cli", PRO_SPECIAL, 0, CLI, 0, + "c", PRO_INT, 33, 0, &ps.com_ind, + "di", PRO_INT, 16, 0, &ps.decl_indent, + "dj", PRO_BOOL, false, ON, &ps.ljust_decl, + "d", PRO_INT, 0, 0, &ps.unindent_displace, + "eei", PRO_BOOL, false, ON, &extra_expression_indent, + "ei", PRO_BOOL, true, ON, &ps.else_if, + "fbc", PRO_FONT, 0, 0, (int *) &blkcomf, + "fbx", PRO_FONT, 0, 0, (int *) &boxcomf, + "fb", PRO_FONT, 0, 0, (int *) &bodyf, + "fc1", PRO_BOOL, true, ON, &format_col1_comments, + "fc", PRO_FONT, 0, 0, (int *) &scomf, + "fk", PRO_FONT, 0, 0, (int *) &keywordf, + "fs", PRO_FONT, 0, 0, (int *) &stringf, + "ip", PRO_BOOL, true, ON, &ps.indent_parameters, + "i", PRO_INT, 8, 0, &ps.ind_size, + "lc", PRO_INT, 0, 0, &block_comment_max_col, + "lp", PRO_BOOL, true, ON, &lineup_to_parens, + "l", PRO_INT, 78, 0, &max_col, + "nbacc", PRO_BOOL, false, OFF, &blanklines_around_conditional_compilation, + "nbadp", PRO_BOOL, false, OFF, &blanklines_after_declarations_at_proctop, + "nbad", PRO_BOOL, false, OFF, &blanklines_after_declarations, + "nbap", PRO_BOOL, false, OFF, &blanklines_after_procs, + "nbbb", PRO_BOOL, false, OFF, &blanklines_before_blockcomments, + "nbc", PRO_BOOL, true, ON, &ps.leave_comma, + "nbs", PRO_BOOL, false, OFF, &Bill_Shannon, + "ncdb", PRO_BOOL, true, OFF, &comment_delimiter_on_blankline, + "nce", PRO_BOOL, true, OFF, &cuddle_else, + "ndj", PRO_BOOL, false, OFF, &ps.ljust_decl, + "neei", PRO_BOOL, false, OFF, &extra_expression_indent, + "nei", PRO_BOOL, true, OFF, &ps.else_if, + "nfc1", PRO_BOOL, true, OFF, &format_col1_comments, + "nip", PRO_BOOL, true, OFF, &ps.indent_parameters, + "nlp", PRO_BOOL, true, OFF, &lineup_to_parens, + "npcs", PRO_BOOL, false, OFF, &proc_calls_space, + "npro", PRO_SPECIAL, 0, IGN, 0, + "npsl", PRO_BOOL, true, OFF, &procnames_start_line, + "nps", PRO_BOOL, false, OFF, &pointer_as_binop, + "nsc", PRO_BOOL, true, OFF, &star_comment_cont, + "nsob", PRO_BOOL, false, OFF, &swallow_optional_blanklines, + "nv", PRO_BOOL, false, OFF, &verbose, + "pcs", PRO_BOOL, false, ON, &proc_calls_space, + "psl", PRO_BOOL, true, ON, &procnames_start_line, + "ps", PRO_BOOL, false, ON, &pointer_as_binop, + "sc", PRO_BOOL, true, ON, &star_comment_cont, + "sob", PRO_BOOL, false, ON, &swallow_optional_blanklines, + "st", PRO_SPECIAL, 0, STDIN, 0, + "troff", PRO_BOOL, false, ON, &troff, + "v", PRO_BOOL, false, ON, &verbose, + /* whew! */ + 0, 0, 0, 0, 0 +}; + +/* + * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments + * given in these files. + */ +set_profile() +{ + register FILE *f; + char fname[BUFSIZ]; + static char prof[] = ".indent.pro"; + + sprintf(fname, "%s/%s", getenv("HOME"), prof); + if ((f = fopen(option_source = fname, "r")) != NULL) { + scan_profile(f); + (void) fclose(f); + } + if ((f = fopen(option_source = prof, "r")) != NULL) { + scan_profile(f); + (void) fclose(f); + } + option_source = "Command line"; +} + +scan_profile(f) + register FILE *f; +{ + register int i; + register char *p; + char buf[BUFSIZ]; + + while (1) { + for (p = buf; (i = getc(f)) != EOF && (*p = i) > ' '; ++p); + if (p != buf) { + *p++ = 0; + if (verbose) + printf("profile: %s\n", buf); + set_option(buf); + } + else if (i == EOF) + return; + } +} + +char *param_start; + +eqin(s1, s2) + register char *s1; + register char *s2; +{ + while (*s1) { + if (*s1++ != *s2++) + return (false); + } + param_start = s2; + return (true); +} + +/* + * Set the defaults. + */ +set_defaults() +{ + register struct pro *p; + + /* + * Because ps.case_indent is a float, we can't initialize it from the + * table: + */ + ps.case_indent = 0.0; /* -cli0.0 */ + for (p = pro; p->p_name; p++) + if (p->p_type != PRO_SPECIAL && p->p_type != PRO_FONT) + *p->p_obj = p->p_default; +} + +set_option(arg) + register char *arg; +{ + register struct pro *p; + extern double atof(); + + arg++; /* ignore leading "-" */ + for (p = pro; p->p_name; p++) + if (*p->p_name == *arg && eqin(p->p_name, arg)) + goto found; + fprintf(stderr, "indent: %s: unknown parameter \"%s\"\n", option_source, arg - 1); + exit(1); +found: + switch (p->p_type) { + + case PRO_SPECIAL: + switch (p->p_special) { + + case IGN: + break; + + case CLI: + if (*param_start == 0) + goto need_param; + ps.case_indent = atof(param_start); + break; + + case STDIN: + if (input == 0) + input = stdin; + if (output == 0) + output = stdout; + break; + + case KEY: + if (*param_start == 0) + goto need_param; + { + register char *str = (char *) malloc(strlen(param_start) + 1); + strcpy(str, param_start); + addkey(str, 4); + } + break; + + default: + fprintf(stderr, "\ +indent: set_option: internal error: p_special %d\n", p->p_special); + exit(1); + } + break; + + case PRO_BOOL: + if (p->p_special == OFF) + *p->p_obj = false; + else + *p->p_obj = true; + break; + + case PRO_INT: + if (!isdigit(*param_start)) { + need_param: + fprintf(stderr, "indent: %s: ``%s'' requires a parameter\n", + option_source, arg - 1); + exit(1); + } + *p->p_obj = atoi(param_start); + break; + + case PRO_FONT: + parsefont((struct fstate *) p->p_obj, param_start); + break; + + default: + fprintf(stderr, "indent: set_option: internal error: p_type %d\n", + p->p_type); + exit(1); + } +} diff --git a/usr.bin/indent/indent.1 b/usr.bin/indent/indent.1 new file mode 100644 index 0000000..c44964a --- /dev/null +++ b/usr.bin/indent/indent.1 @@ -0,0 +1,452 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 1976 Board of Trustees of the University of Illinois. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)indent.1 8.1 (Berkeley) 7/1/93 +.\" +.Dd July 1, 1993 +.Dt INDENT 1 +.Os BSD 4.2 +.Sh NAME +.Nm indent +.Nd indent and format C program source +.Sh SYNOPSIS +.Nm indent +.Op Ar input-file Op Ar output-file +.Op Fl bad | Fl nbad +.Op Fl bap | Fl nbap +.Bk -words +.Op Fl bbb | Fl nbbb +.Ek +.Op Fl \&bc | Fl nbc +.Op Fl \&bl +.Op Fl \&br +.Op Fl c Ns Ar n +.Op Fl \&cd Ns Ar n +.Bk -words +.Op Fl cdb | Fl ncdb +.Ek +.Op Fl \&ce | Fl nce +.Op Fl \&ci Ns Ar n +.Op Fl cli Ns Ar n +.Op Fl d Ns Ar n +.Op Fl \&di Ns Ar n +.Bk -words +.Op Fl fc1 | Fl nfc1 +.Ek +.Op Fl i Ns Ar n +.Op Fl \&ip | Fl nip +.Op Fl l Ns Ar n +.Op Fl \&lc Ns Ar n +.Op Fl \&lp | Fl nlp +.Op Fl npro +.Op Fl pcs | Fl npcs +.Op Fl psl | Fl npsl +.Op Fl \&sc | Fl nsc +.Bk -words +.Op Fl sob | Fl nsob +.Ek +.Op Fl \&st +.Op Fl troff +.Op Fl v | Fl \&nv +.Sh DESCRIPTION +.Nm Indent +is a +.Ar C +program formatter. It reformats the +.Ar C +program in the +.Ar input-file +according to the switches. The switches which can be +specified are described below. They may appear before or after the file +names. +.Pp +.Sy NOTE : +If you only specify an +.Ar input-file , +the formatting is +done `in-place', that is, the formatted file is written back into +.Ar input-file +and a backup copy of +.Ar input-file +is written in the current directory. If +.Ar input-file +is named +.Sq Pa /blah/blah/file , +the backup file is named +.Pa file.BAK . +.Pp +If +.Ar output-file +is specified, +.Nm indent +checks to make sure it is different from +.Ar input-file . +.Pp +The options listed below control the formatting style imposed by +.Nm indent . +.Bl -tag -width Op +.It Fl bad , nbad +If +.Fl bad +is specified, a blank line is forced after every block of +declarations. Default: +.Fl nbad . +.It Fl bap , nbap +If +.Fl bap +is specified, a blank line is forced after every procedure body. Default: +.Fl nbap . +.It Fl bbb , nbbb +If +.Fl bbb +is specified, a blank line is forced before every block comment. Default: +.Fl nbbb . +.It Fl \&bc , nbc +If +.Fl \&bc +is specified, then a newline is forced after each comma in a declaration. +.Fl nbc +turns off this option. The default is +.Fl \&bc . +.It Fl \&br , \&bl +Specifying +.Fl \&bl +lines up compound statements like this: +.ne 4 +.Bd -literal -offset indent +if (...) +{ + code +} +.Ed +.Pp +Specifying +.Fl \&br +(the default) makes them look like this: +.ne 3 +.Bd -literal -offset indent +if (...) { + code +} +.Ed +.Pp +.It Fl c n +The column in which comments on code start. The default is 33. +.It Fl cd n +The column in which comments on declarations start. The default +is for these comments to start in the same column as those on code. +.It Fl cdb , ncdb +Enables (disables) the placement of comment delimiters on blank lines. With +this option enabled, comments look like this: +.Bd -literal -offset indent +.ne 3 + /* + * this is a comment + */ +.Ed +.Pp +Rather than like this: +.Bd -literal -offset indent + /* this is a comment */ +.Ed +.Pp +This only affects block comments, not comments to the right of +code. The default is +.Fl cdb . +.It Fl ce , nce +Enables (disables) forcing `else's to cuddle up to the immediately preceding +`}'. The default is +.Fl \&ce . +.It Fl \&ci Ns Ar n +Sets the continuation indent to be +.Ar n . +Continuation +lines will be indented that far from the beginning of the first line of the +statement. Parenthesized expressions have extra indentation added to +indicate the nesting, unless +.Fl \&lp +is in effect. +.Fl \&ci +defaults to the same value as +.Fl i . +.It Fl cli Ns Ar n +Causes case labels to be indented +.Ar n +tab stops to the right of the containing +.Ic switch +statement. +.Fl cli0 .5 +causes case labels to be indented half a tab stop. The +default is +.Fl cli0 . +.It Fl d Ns Ar n +Controls the placement of comments which are not to the +right of code. The default +.Fl \&d\&1 +means that such comments are placed one indentation level to the +left of code. Specifying +.Fl \&d\&0 +lines up these comments with the code. See the section on comment +indentation below. +.It Fl \&di Ns Ar n +Specifies the indentation, in character positions, from a declaration keyword +to the following identifier. The default is +.Fl di16 . +.It Fl dj , ndj +.Fl \&dj +left justifies declarations. +.Fl ndj +indents declarations the same as code. The default is +.Fl ndj . +.It Fl \&ei , nei +Enables (disables) special +.Ic else-if +processing. If it's enabled, an +.Ic if +following an +.Ic else +will have the same indentation as the preceding +.Ic \&if +statement. +.It Fl fc1 , nfc1 +Enables (disables) the formatting of comments that start in column 1. +Often, comments whose leading `/' is in column 1 have been carefully +hand formatted by the programmer. In such cases, +.Fl nfc1 +should be +used. The default is +.Fl fc1 . +.It Fl i Ns Ar n +The number of spaces for one indentation level. The default is 4. +.It Fl \&ip , nip +Enables (disables) the indentation of parameter declarations from the left +margin. The default is +.Fl \&ip . +.It Fl l Ns Ar n +Maximum length of an output line. The default is 75. +.It Fl \&lp , nlp +Lines up code surrounded by parenthesis in continuation lines. If a line +has a left paren which is not closed on that line, then continuation lines +will be lined up to start at the character position just after the left +paren. For example, here is how a piece of continued code looks with +.Fl nlp +in effect: +.ne 2 +.Bd -literal -offset indent +p1 = first_procedure(second_procedure(p2, p3), +\ \ third_procedure(p4,p5)); +.Ed +.Pp +.ne 5 +With +.Fl lp +in effect (the default) the code looks somewhat clearer: +.Bd -literal -offset indent +p1\ =\ first_procedure(second_procedure(p2,\ p3), +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,p5)); +.Ed +.Pp +.ne 5 +Inserting two more newlines we get: +.Bd -literal -offset indent +p1\ =\ first_procedure(second_procedure(p2, +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p3), +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4 +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p5)); +.Ed +.It Fl npro +Causes the profile files, +.Sq Pa ./.indent.pro +and +.Sq Pa ~/.indent.pro , +to be ignored. +.It Fl pcs , npcs +If true +.Pq Fl pcs +all procedure calls will have a space inserted between +the name and the `('. The default is +.Fl npcs . +.It Fl psl , npsl +If true +.Pq Fl psl +the names of procedures being defined are placed in +column 1 \- their types, if any, will be left on the previous lines. The +default is +.Fl psl . +.It Fl \&sc , nsc +Enables (disables) the placement of asterisks (`*'s) at the left edge of all +comments. +.It Fl sob , nsob +If +.Fl sob +is specified, indent will swallow optional blank lines. You can use this to +get rid of blank lines after declarations. Default: +.Fl nsob . +.It Fl \&st +Causes +.Nm indent +to take its input from stdin, and put its output to stdout. +.It Fl T Ns Ar typename +Adds +.Ar typename +to the list of type keywords. Names accumulate: +.Fl T +can be specified more than once. You need to specify all the typenames that +appear in your program that are defined by +.Ic typedef +\- nothing will be +harmed if you miss a few, but the program won't be formatted as nicely as +it should. This sounds like a painful thing to have to do, but it's really +a symptom of a problem in C: +.Ic typedef +causes a syntactic change in the +language and +.Nm indent +can't find all +instances of +.Ic typedef . +.It Fl troff +Causes +.Nm indent +to format the program for processing by +.Xr troff 1 . +It will produce a fancy +listing in much the same spirit as +.Xr vgrind 1 . +If the output file is not specified, the default is standard output, +rather than formatting in place. +.It Fl v , \&nv +.Fl v +turns on `verbose' mode; +.Fl \&nv +turns it off. When in verbose mode, +.Nm indent +reports when it splits one line of input into two or more lines of output, +and gives some size statistics at completion. The default is +.Fl \&nv . +.El +.Pp +You may set up your own `profile' of defaults to +.Nm indent +by creating a file called +.Pa .indent.pro +in your login directory and/or the current directory and including +whatever switches you like. A `.indent.pro' in the current directory takes +precedence over the one in your login directory. If +.Nm indent +is run and a profile file exists, then it is read to set up the program's +defaults. Switches on the command line, though, always override profile +switches. The switches should be separated by spaces, tabs or newlines. +.Pp +.Ss Comments +.Sq Em Box +.Em comments . +.Nm Indent +assumes that any comment with a dash or star immediately after the start of +comment (that is, `/*\-' or `/**') is a comment surrounded by a box of stars. +Each line of such a comment is left unchanged, except that its indentation +may be adjusted to account for the change in indentation of the first line +of the comment. +.Pp +.Em Straight text . +All other comments are treated as straight text. +.Nm Indent +fits as many words (separated by blanks, tabs, or newlines) on a +line as possible. Blank lines break paragraphs. +.Pp +.Ss Comment indentation +If a comment is on a line with code it is started in the `comment column', +which is set by the +.Fl c Ns Ns Ar n +command line parameter. Otherwise, the comment is started at +.Ar n +indentation levels less than where code is currently being placed, where +.Ar n +is specified by the +.Fl d Ns Ns Ar n +command line parameter. If the code on a line extends past the comment +column, the comment starts further to the right, and the right margin may be +automatically extended in extreme cases. +.Pp +.Ss Preprocessor lines +In general, +.Nm indent +leaves preprocessor lines alone. The only +reformatting that it will do is to straighten up trailing comments. It +leaves embedded comments alone. Conditional compilation +.Pq Ic #ifdef...#endif +is recognized and +.Nm indent +attempts to correctly +compensate for the syntactic peculiarities introduced. +.Pp +.Ss C syntax +.Nm Indent +understands a substantial amount about the syntax of C, but it +has a `forgiving' parser. It attempts to cope with the usual sorts of +incomplete and misformed syntax. In particular, the use of macros like: +.Pp +.Dl #define forever for(;;) +.Pp +is handled properly. +.Sh ENVIRONMENT +.Nm Indent +uses the +.Ev HOME +environment variable. +.Sh FILES +.Bl -tag -width "./.indent.pro" -compact +.It Pa ./.indent.pro +profile file +.It Pa ~/.indent.pro +profile file +.El +.Sh HISTORY +The +.Nm indent +command appeared in +.Bx 4.2 . +.Sh BUGS +.Nm Indent +has even more switches than +.Xr ls 1 . +.Pp +.ne 5 +A common mistake that often causes grief is typing: +.Pp +.Dl indent *.c +.Pp +to the shell in an attempt to indent all the +.Nm C +programs in a directory. +This is probably a bug, not a feature. diff --git a/usr.bin/indent/indent.c b/usr.bin/indent/indent.c new file mode 100644 index 0000000..132d21f --- /dev/null +++ b/usr.bin/indent/indent.c @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * 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. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\ +@(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\ +@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)indent.c 5.17 (Berkeley) 6/7/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include "indent_globs.h" +#include "indent_codes.h" +#include + +char *in_name = "Standard Input"; /* will always point to name of input + * file */ +char *out_name = "Standard Output"; /* will always point to name + * of output file */ +char bakfile[MAXPATHLEN] = ""; + +main(argc, argv) + int argc; + char **argv; +{ + + extern int found_err; /* flag set in diag() on error */ + int dec_ind; /* current indentation for declarations */ + int di_stack[20]; /* a stack of structure indentation levels */ + int flushed_nl; /* used when buffering up comments to remember + * that a newline was passed over */ + int force_nl; /* when true, code must be broken */ + int hd_type; /* used to store type of stmt for if (...), + * for (...), etc */ + register int i; /* local loop counter */ + int scase; /* set to true when we see a case, so we will + * know what to do with the following colon */ + int sp_sw; /* when true, we are in the expressin of + * if(...), while(...), etc. */ + int squest; /* when this is positive, we have seen a ? + * without the matching : in a ?: + * construct */ + register char *t_ptr; /* used for copying tokens */ + int type_code; /* the type of token, returned by lexi */ + + int last_else = 0; /* true iff last keyword was an else */ + + + /*-----------------------------------------------*\ + | INITIALIZATION | + \*-----------------------------------------------*/ + + + ps.p_stack[0] = stmt; /* this is the parser's stack */ + ps.last_nl = true; /* this is true if the last thing scanned was + * a newline */ + ps.last_token = semicolon; + combuf = (char *) malloc(bufsize); + labbuf = (char *) malloc(bufsize); + codebuf = (char *) malloc(bufsize); + tokenbuf = (char *) malloc(bufsize); + l_com = combuf + bufsize - 5; + l_lab = labbuf + bufsize - 5; + l_code = codebuf + bufsize - 5; + l_token = tokenbuf + bufsize - 5; + combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and + * comment buffers */ + combuf[1] = codebuf[1] = labbuf[1] = '\0'; + ps.else_if = 1; /* Default else-if special processing to on */ + s_lab = e_lab = labbuf + 1; + s_code = e_code = codebuf + 1; + s_com = e_com = combuf + 1; + s_token = e_token = tokenbuf + 1; + + in_buffer = (char *) malloc(10); + in_buffer_limit = in_buffer + 8; + buf_ptr = buf_end = in_buffer; + line_no = 1; + had_eof = ps.in_decl = ps.decl_on_line = break_comma = false; + sp_sw = force_nl = false; + ps.in_or_st = false; + ps.bl_line = true; + dec_ind = 0; + di_stack[ps.dec_nest = 0] = 0; + ps.want_blank = ps.in_stmt = ps.ind_stmt = false; + + + scase = ps.pcase = false; + squest = 0; + sc_end = 0; + bp_save = 0; + be_save = 0; + + output = 0; + + + + /*--------------------------------------------------*\ + | COMMAND LINE SCAN | + \*--------------------------------------------------*/ + +#ifdef undef + max_col = 78; /* -l78 */ + lineup_to_parens = 1; /* -lp */ + ps.ljust_decl = 0; /* -ndj */ + ps.com_ind = 33; /* -c33 */ + star_comment_cont = 1; /* -sc */ + ps.ind_size = 8; /* -i8 */ + verbose = 0; + ps.decl_indent = 16; /* -di16 */ + ps.indent_parameters = 1; /* -ip */ + ps.decl_com_ind = 0; /* if this is not set to some positive value + * by an arg, we will set this equal to + * ps.com_ind */ + btype_2 = 1; /* -br */ + cuddle_else = 1; /* -ce */ + ps.unindent_displace = 0; /* -d0 */ + ps.case_indent = 0; /* -cli0 */ + format_col1_comments = 1; /* -fc1 */ + procnames_start_line = 1; /* -psl */ + proc_calls_space = 0; /* -npcs */ + comment_delimiter_on_blankline = 1; /* -cdb */ + ps.leave_comma = 1; /* -nbc */ +#endif + + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "-npro") == 0) + break; + set_defaults(); + if (i >= argc) + set_profile(); + + for (i = 1; i < argc; ++i) { + + /* + * look thru args (if any) for changes to defaults + */ + if (argv[i][0] != '-') {/* no flag on parameter */ + if (input == 0) { /* we must have the input file */ + in_name = argv[i]; /* remember name of input file */ + input = fopen(in_name, "r"); + if (input == 0) /* check for open error */ + err(in_name); + continue; + } + else if (output == 0) { /* we have the output file */ + out_name = argv[i]; /* remember name of output file */ + if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite + * the file */ + fprintf(stderr, "indent: input and output files must be different\n"); + exit(1); + } + output = fopen(out_name, "w"); + if (output == 0) /* check for create error */ + err(out_name); + continue; + } + fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]); + exit(1); + } + else + set_option(argv[i]); + } /* end of for */ + if (input == 0) { + fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n"); + exit(1); + } + if (output == 0) + if (troff) + output = stdout; + else { + out_name = in_name; + bakcopy(); + } + if (ps.com_ind <= 1) + ps.com_ind = 2; /* dont put normal comments before column 2 */ + if (troff) { + if (bodyf.font[0] == 0) + parsefont(&bodyf, "R"); + if (scomf.font[0] == 0) + parsefont(&scomf, "I"); + if (blkcomf.font[0] == 0) + blkcomf = scomf, blkcomf.size += 2; + if (boxcomf.font[0] == 0) + boxcomf = blkcomf; + if (stringf.font[0] == 0) + parsefont(&stringf, "L"); + if (keywordf.font[0] == 0) + parsefont(&keywordf, "B"); + writefdef(&bodyf, 'B'); + writefdef(&scomf, 'C'); + writefdef(&blkcomf, 'L'); + writefdef(&boxcomf, 'X'); + writefdef(&stringf, 'S'); + writefdef(&keywordf, 'K'); + } + if (block_comment_max_col <= 0) + block_comment_max_col = max_col; + if (ps.decl_com_ind <= 0) /* if not specified by user, set this */ + ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind; + if (continuation_indent == 0) + continuation_indent = ps.ind_size; + fill_buffer(); /* get first batch of stuff into input buffer */ + + parse(semicolon); + { + register char *p = buf_ptr; + register col = 1; + + while (1) { + if (*p == ' ') + col++; + else if (*p == '\t') + col = ((col - 1) & ~7) + 9; + else + break; + p++; + } + if (col > ps.ind_size) + ps.ind_level = ps.i_l_follow = col / ps.ind_size; + } + if (troff) { + register char *p = in_name, + *beg = in_name; + + while (*p) + if (*p++ == '/') + beg = p; + fprintf(output, ".Fn \"%s\"\n", beg); + } + /* + * START OF MAIN LOOP + */ + + while (1) { /* this is the main loop. it will go until we + * reach eof */ + int is_procname; + + type_code = lexi(); /* lexi reads one token. The actual + * characters read are stored in "token". lexi + * returns a code indicating the type of token */ + is_procname = ps.procname[0]; + + /* + * The following code moves everything following an if (), while (), + * else, etc. up to the start of the following stmt to a buffer. This + * allows proper handling of both kinds of brace placement. + */ + + flushed_nl = false; + while (ps.search_brace) { /* if we scanned an if(), while(), + * etc., we might need to copy stuff + * into a buffer we must loop, copying + * stuff into save_com, until we find + * the start of the stmt which follows + * the if, or whatever */ + switch (type_code) { + case newline: + ++line_no; + flushed_nl = true; + case form_feed: + break; /* form feeds and newlines found here will be + * ignored */ + + case lbrace: /* this is a brace that starts the compound + * stmt */ + if (sc_end == 0) { /* ignore buffering if a comment wasnt + * stored up */ + ps.search_brace = false; + goto check_type; + } + if (btype_2) { + save_com[0] = '{'; /* we either want to put the brace + * right after the if */ + goto sw_buffer; /* go to common code to get out of + * this loop */ + } + case comment: /* we have a comment, so we must copy it into + * the buffer */ + if (!flushed_nl || sc_end != 0) { + if (sc_end == 0) { /* if this is the first comment, we + * must set up the buffer */ + save_com[0] = save_com[1] = ' '; + sc_end = &(save_com[2]); + } + else { + *sc_end++ = '\n'; /* add newline between + * comments */ + *sc_end++ = ' '; + --line_no; + } + *sc_end++ = '/'; /* copy in start of comment */ + *sc_end++ = '*'; + + for (;;) { /* loop until we get to the end of the comment */ + *sc_end = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + + if (*sc_end++ == '*' && *buf_ptr == '/') + break; /* we are at end of comment */ + + if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer + * overflow */ + diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever."); + fflush(output); + exit(1); + } + } + *sc_end++ = '/'; /* add ending slash */ + if (++buf_ptr >= buf_end) /* get past / in buffer */ + fill_buffer(); + break; + } + default: /* it is the start of a normal statment */ + if (flushed_nl) /* if we flushed a newline, make sure it is + * put back */ + force_nl = true; + if (type_code == sp_paren && *token == 'i' + && last_else && ps.else_if + || type_code == sp_nparen && *token == 'e' + && e_code != s_code && e_code[-1] == '}') + force_nl = false; + + if (sc_end == 0) { /* ignore buffering if comment wasnt + * saved up */ + ps.search_brace = false; + goto check_type; + } + if (force_nl) { /* if we should insert a nl here, put it into + * the buffer */ + force_nl = false; + --line_no; /* this will be re-increased when the nl is + * read from the buffer */ + *sc_end++ = '\n'; + *sc_end++ = ' '; + if (verbose && !flushed_nl) /* print error msg if the line + * was not already broken */ + diag(0, "Line broken"); + flushed_nl = false; + } + for (t_ptr = token; *t_ptr; ++t_ptr) + *sc_end++ = *t_ptr; /* copy token into temp buffer */ + ps.procname[0] = 0; + + sw_buffer: + ps.search_brace = false; /* stop looking for start of + * stmt */ + bp_save = buf_ptr; /* save current input buffer */ + be_save = buf_end; + buf_ptr = save_com; /* fix so that subsequent calls to + * lexi will take tokens out of + * save_com */ + *sc_end++ = ' ';/* add trailing blank, just in case */ + buf_end = sc_end; + sc_end = 0; + break; + } /* end of switch */ + if (type_code != 0) /* we must make this check, just in case there + * was an unexpected EOF */ + type_code = lexi(); /* read another token */ + /* if (ps.search_brace) ps.procname[0] = 0; */ + if ((is_procname = ps.procname[0]) && flushed_nl + && !procnames_start_line && ps.in_decl + && type_code == ident) + flushed_nl = 0; + } /* end of while (search_brace) */ + last_else = 0; +check_type: + if (type_code == 0) { /* we got eof */ + if (s_lab != e_lab || s_code != e_code + || s_com != e_com) /* must dump end of line */ + dump_line(); + if (ps.tos > 1) /* check for balanced braces */ + diag(1, "Stuff missing from end of file."); + + if (verbose) { + printf("There were %d output lines and %d comments\n", + ps.out_lines, ps.out_coms); + printf("(Lines with comments)/(Lines with code): %6.3f\n", + (1.0 * ps.com_lines) / code_lines); + } + fflush(output); + exit(found_err); + } + if ( + (type_code != comment) && + (type_code != newline) && + (type_code != preesc) && + (type_code != form_feed)) { + if (force_nl && + (type_code != semicolon) && + (type_code != lbrace || !btype_2)) { + /* we should force a broken line here */ + if (verbose && !flushed_nl) + diag(0, "Line broken"); + flushed_nl = false; + dump_line(); + ps.want_blank = false; /* dont insert blank at line start */ + force_nl = false; + } + ps.in_stmt = true; /* turn on flag which causes an extra level of + * indentation. this is turned off by a ; or + * '}' */ + if (s_com != e_com) { /* the turkey has embedded a comment + * in a line. fix it */ + *e_code++ = ' '; + for (t_ptr = s_com; *t_ptr; ++t_ptr) { + CHECK_SIZE_CODE; + *e_code++ = *t_ptr; + } + *e_code++ = ' '; + *e_code = '\0'; /* null terminate code sect */ + ps.want_blank = false; + e_com = s_com; + } + } + else if (type_code != comment) /* preserve force_nl thru a comment */ + force_nl = false; /* cancel forced newline after newline, form + * feed, etc */ + + + + /*-----------------------------------------------------*\ + | do switch on type of token scanned | + \*-----------------------------------------------------*/ + CHECK_SIZE_CODE; + switch (type_code) { /* now, decide what to do with the token */ + + case form_feed: /* found a form feed in line */ + ps.use_ff = true; /* a form feed is treated much like a newline */ + dump_line(); + ps.want_blank = false; + break; + + case newline: + if (ps.last_token != comma || ps.p_l_follow > 0 + || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) { + dump_line(); + ps.want_blank = false; + } + ++line_no; /* keep track of input line number */ + break; + + case lparen: /* got a '(' or '[' */ + ++ps.p_l_follow; /* count parens to make Healy happy */ + if (ps.want_blank && *token != '[' && + (ps.last_token != ident || proc_calls_space + || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon)))) + *e_code++ = ' '; + if (ps.in_decl && !ps.block_init) + if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) { + ps.dumped_decl_indent = 1; + sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token); + e_code += strlen(e_code); + } + else { + while ((e_code - s_code) < dec_ind) { + CHECK_SIZE_CODE; + *e_code++ = ' '; + } + *e_code++ = token[0]; + } + else + *e_code++ = token[0]; + ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code; + if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent + && ps.paren_indents[0] < 2 * ps.ind_size) + ps.paren_indents[0] = 2 * ps.ind_size; + ps.want_blank = false; + if (ps.in_or_st && *token == '(' && ps.tos <= 2) { + /* + * this is a kluge to make sure that declarations will be + * aligned right if proc decl has an explicit type on it, i.e. + * "int a(x) {..." + */ + parse(semicolon); /* I said this was a kluge... */ + ps.in_or_st = false; /* turn off flag for structure decl or + * initialization */ + } + if (ps.sizeof_keyword) + ps.sizeof_mask |= 1 << ps.p_l_follow; + break; + + case rparen: /* got a ')' or ']' */ + rparen_count--; + if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) { + ps.last_u_d = true; + ps.cast_mask &= (1 << ps.p_l_follow) - 1; + } + ps.sizeof_mask &= (1 << ps.p_l_follow) - 1; + if (--ps.p_l_follow < 0) { + ps.p_l_follow = 0; + diag(0, "Extra %c", *token); + } + if (e_code == s_code) /* if the paren starts the line */ + ps.paren_level = ps.p_l_follow; /* then indent it */ + + *e_code++ = token[0]; + ps.want_blank = true; + + if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if + * (...), or some such */ + sp_sw = false; + force_nl = true;/* must force newline after if */ + ps.last_u_d = true; /* inform lexi that a following + * operator is unary */ + ps.in_stmt = false; /* dont use stmt continuation + * indentation */ + + parse(hd_type); /* let parser worry about if, or whatever */ + } + ps.search_brace = btype_2; /* this should insure that constructs + * such as main(){...} and int[]{...} + * have their braces put in the right + * place */ + break; + + case unary_op: /* this could be any unary operation */ + if (ps.want_blank) + *e_code++ = ' '; + + if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) { + sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token); + ps.dumped_decl_indent = 1; + e_code += strlen(e_code); + } + else { + char *res = token; + + if (ps.in_decl && !ps.block_init) { /* if this is a unary op + * in a declaration, we + * should indent this + * token */ + for (i = 0; token[i]; ++i); /* find length of token */ + while ((e_code - s_code) < (dec_ind - i)) { + CHECK_SIZE_CODE; + *e_code++ = ' '; /* pad it */ + } + } + if (troff && token[0] == '-' && token[1] == '>') + res = "\\(->"; + for (t_ptr = res; *t_ptr; ++t_ptr) { + CHECK_SIZE_CODE; + *e_code++ = *t_ptr; + } + } + ps.want_blank = false; + break; + + case binary_op: /* any binary operation */ + if (ps.want_blank) + *e_code++ = ' '; + { + char *res = token; + + if (troff) + switch (token[0]) { + case '<': + if (token[1] == '=') + res = "\\(<="; + break; + case '>': + if (token[1] == '=') + res = "\\(>="; + break; + case '!': + if (token[1] == '=') + res = "\\(!="; + break; + case '|': + if (token[1] == '|') + res = "\\(br\\(br"; + else if (token[1] == 0) + res = "\\(br"; + break; + } + for (t_ptr = res; *t_ptr; ++t_ptr) { + CHECK_SIZE_CODE; + *e_code++ = *t_ptr; /* move the operator */ + } + } + ps.want_blank = true; + break; + + case postop: /* got a trailing ++ or -- */ + *e_code++ = token[0]; + *e_code++ = token[1]; + ps.want_blank = true; + break; + + case question: /* got a ? */ + squest++; /* this will be used when a later colon + * appears so we can distinguish the + * ?: construct */ + if (ps.want_blank) + *e_code++ = ' '; + *e_code++ = '?'; + ps.want_blank = true; + break; + + case casestmt: /* got word 'case' or 'default' */ + scase = true; /* so we can process the later colon properly */ + goto copy_id; + + case colon: /* got a ':' */ + if (squest > 0) { /* it is part of the ?: construct */ + --squest; + if (ps.want_blank) + *e_code++ = ' '; + *e_code++ = ':'; + ps.want_blank = true; + break; + } + if (ps.in_decl) { + *e_code++ = ':'; + ps.want_blank = false; + break; + } + ps.in_stmt = false; /* seeing a label does not imply we are in a + * stmt */ + for (t_ptr = s_code; *t_ptr; ++t_ptr) + *e_lab++ = *t_ptr; /* turn everything so far into a label */ + e_code = s_code; + *e_lab++ = ':'; + *e_lab++ = ' '; + *e_lab = '\0'; + + force_nl = ps.pcase = scase; /* ps.pcase will be used by + * dump_line to decide how to + * indent the label. force_nl + * will force a case n: to be + * on a line by itself */ + scase = false; + ps.want_blank = false; + break; + + case semicolon: /* got a ';' */ + ps.in_or_st = false;/* we are not in an initialization or + * structure declaration */ + scase = false; /* these will only need resetting in a error */ + squest = 0; + if (ps.last_token == rparen && rparen_count == 0) + ps.in_parameter_declaration = 0; + ps.cast_mask = 0; + ps.sizeof_mask = 0; + ps.block_init = 0; + ps.block_init_level = 0; + ps.just_saw_decl--; + + if (ps.in_decl && s_code == e_code && !ps.block_init) + while ((e_code - s_code) < (dec_ind - 1)) { + CHECK_SIZE_CODE; + *e_code++ = ' '; + } + + ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level + * structure declaration, we + * arent any more */ + + if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) { + + /* + * This should be true iff there were unbalanced parens in the + * stmt. It is a bit complicated, because the semicolon might + * be in a for stmt + */ + diag(1, "Unbalanced parens"); + ps.p_l_follow = 0; + if (sp_sw) { /* this is a check for a if, while, etc. with + * unbalanced parens */ + sp_sw = false; + parse(hd_type); /* dont lose the if, or whatever */ + } + } + *e_code++ = ';'; + ps.want_blank = true; + ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the + * middle of a stmt */ + + if (!sp_sw) { /* if not if for (;;) */ + parse(semicolon); /* let parser know about end of stmt */ + force_nl = true;/* force newline after a end of stmt */ + } + break; + + case lbrace: /* got a '{' */ + ps.in_stmt = false; /* dont indent the {} */ + if (!ps.block_init) + force_nl = true;/* force other stuff on same line as '{' onto + * new line */ + else if (ps.block_init_level <= 0) + ps.block_init_level = 1; + else + ps.block_init_level++; + + if (s_code != e_code && !ps.block_init) { + if (!btype_2) { + dump_line(); + ps.want_blank = false; + } + else if (ps.in_parameter_declaration && !ps.in_or_st) { + ps.i_l_follow = 0; + dump_line(); + ps.want_blank = false; + } + } + if (ps.in_parameter_declaration) + prefix_blankline_requested = 0; + + if (ps.p_l_follow > 0) { /* check for preceeding unbalanced + * parens */ + diag(1, "Unbalanced parens"); + ps.p_l_follow = 0; + if (sp_sw) { /* check for unclosed if, for, etc. */ + sp_sw = false; + parse(hd_type); + ps.ind_level = ps.i_l_follow; + } + } + if (s_code == e_code) + ps.ind_stmt = false; /* dont put extra indentation on line + * with '{' */ + if (ps.in_decl && ps.in_or_st) { /* this is either a structure + * declaration or an init */ + di_stack[ps.dec_nest++] = dec_ind; + /* ? dec_ind = 0; */ + } + else { + ps.decl_on_line = false; /* we cant be in the middle of + * a declaration, so dont do + * special indentation of + * comments */ + if (blanklines_after_declarations_at_proctop + && ps.in_parameter_declaration) + postfix_blankline_requested = 1; + ps.in_parameter_declaration = 0; + } + dec_ind = 0; + parse(lbrace); /* let parser know about this */ + if (ps.want_blank) /* put a blank before '{' if '{' is not at + * start of line */ + *e_code++ = ' '; + ps.want_blank = false; + *e_code++ = '{'; + ps.just_saw_decl = 0; + break; + + case rbrace: /* got a '}' */ + if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be + * omitted in + * declarations */ + parse(semicolon); + if (ps.p_l_follow) {/* check for unclosed if, for, else. */ + diag(1, "Unbalanced parens"); + ps.p_l_follow = 0; + sp_sw = false; + } + ps.just_saw_decl = 0; + ps.block_init_level--; + if (s_code != e_code && !ps.block_init) { /* '}' must be first on + * line */ + if (verbose) + diag(0, "Line broken"); + dump_line(); + } + *e_code++ = '}'; + ps.want_blank = true; + ps.in_stmt = ps.ind_stmt = false; + if (ps.dec_nest > 0) { /* we are in multi-level structure + * declaration */ + dec_ind = di_stack[--ps.dec_nest]; + if (ps.dec_nest == 0 && !ps.in_parameter_declaration) + ps.just_saw_decl = 2; + ps.in_decl = true; + } + prefix_blankline_requested = 0; + parse(rbrace); /* let parser know about this */ + ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead + && ps.il[ps.tos] >= ps.ind_level; + if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0) + postfix_blankline_requested = 1; + break; + + case swstmt: /* got keyword "switch" */ + sp_sw = true; + hd_type = swstmt; /* keep this for when we have seen the + * expression */ + goto copy_id; /* go move the token into buffer */ + + case sp_paren: /* token is if, while, for */ + sp_sw = true; /* the interesting stuff is done after the + * expression is scanned */ + hd_type = (*token == 'i' ? ifstmt : + (*token == 'w' ? whilestmt : forstmt)); + + /* + * remember the type of header for later use by parser + */ + goto copy_id; /* copy the token into line */ + + case sp_nparen: /* got else, do */ + ps.in_stmt = false; + if (*token == 'e') { + if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) { + if (verbose) + diag(0, "Line broken"); + dump_line();/* make sure this starts a line */ + ps.want_blank = false; + } + force_nl = true;/* also, following stuff must go onto new line */ + last_else = 1; + parse(elselit); + } + else { + if (e_code != s_code) { /* make sure this starts a line */ + if (verbose) + diag(0, "Line broken"); + dump_line(); + ps.want_blank = false; + } + force_nl = true;/* also, following stuff must go onto new line */ + last_else = 0; + parse(dolit); + } + goto copy_id; /* move the token into line */ + + case decl: /* we have a declaration type (int, register, + * etc.) */ + parse(decl); /* let parser worry about indentation */ + if (ps.last_token == rparen && ps.tos <= 1) { + ps.in_parameter_declaration = 1; + if (s_code != e_code) { + dump_line(); + ps.want_blank = 0; + } + } + if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) { + ps.ind_level = ps.i_l_follow = 1; + ps.ind_stmt = 0; + } + ps.in_or_st = true; /* this might be a structure or initialization + * declaration */ + ps.in_decl = ps.decl_on_line = true; + if ( /* !ps.in_or_st && */ ps.dec_nest <= 0) + ps.just_saw_decl = 2; + prefix_blankline_requested = 0; + for (i = 0; token[i++];); /* get length of token */ + + /* + * dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent + * : i); + */ + dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i; + goto copy_id; + + case ident: /* got an identifier or constant */ + if (ps.in_decl) { /* if we are in a declaration, we must indent + * identifier */ + if (ps.want_blank) + *e_code++ = ' '; + ps.want_blank = false; + if (is_procname == 0 || !procnames_start_line) { + if (!ps.block_init) + if (troff && !ps.dumped_decl_indent) { + sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7); + ps.dumped_decl_indent = 1; + e_code += strlen(e_code); + } + else + while ((e_code - s_code) < dec_ind) { + CHECK_SIZE_CODE; + *e_code++ = ' '; + } + } + else { + if (dec_ind && s_code != e_code) + dump_line(); + dec_ind = 0; + ps.want_blank = false; + } + } + else if (sp_sw && ps.p_l_follow == 0) { + sp_sw = false; + force_nl = true; + ps.last_u_d = true; + ps.in_stmt = false; + parse(hd_type); + } + copy_id: + if (ps.want_blank) + *e_code++ = ' '; + if (troff && ps.its_a_keyword) { + e_code = chfont(&bodyf, &keywordf, e_code); + for (t_ptr = token; *t_ptr; ++t_ptr) { + CHECK_SIZE_CODE; + *e_code++ = keywordf.allcaps && islower(*t_ptr) + ? toupper(*t_ptr) : *t_ptr; + } + e_code = chfont(&keywordf, &bodyf, e_code); + } + else + for (t_ptr = token; *t_ptr; ++t_ptr) { + CHECK_SIZE_CODE; + *e_code++ = *t_ptr; + } + ps.want_blank = true; + break; + + case period: /* treat a period kind of like a binary + * operation */ + *e_code++ = '.'; /* move the period into line */ + ps.want_blank = false; /* dont put a blank after a period */ + break; + + case comma: + ps.want_blank = (s_code != e_code); /* only put blank after comma + * if comma does not start the + * line */ + if (ps.in_decl && is_procname == 0 && !ps.block_init) + while ((e_code - s_code) < (dec_ind - 1)) { + CHECK_SIZE_CODE; + *e_code++ = ' '; + } + + *e_code++ = ','; + if (ps.p_l_follow == 0) { + if (ps.block_init_level <= 0) + ps.block_init = 0; + if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8)) + force_nl = true; + } + break; + + case preesc: /* got the character '#' */ + if ((s_com != e_com) || + (s_lab != e_lab) || + (s_code != e_code)) + dump_line(); + *e_lab++ = '#'; /* move whole line to 'label' buffer */ + { + int in_comment = 0; + int com_start = 0; + char quote = 0; + int com_end = 0; + + while (*buf_ptr == ' ' || *buf_ptr == '\t') { + buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + } + while (*buf_ptr != '\n' || in_comment) { + CHECK_SIZE_LAB; + *e_lab = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + switch (*e_lab++) { + case BACKSLASH: + if (troff) + *e_lab++ = BACKSLASH; + if (!in_comment) { + *e_lab++ = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + } + break; + case '/': + if (*buf_ptr == '*' && !in_comment && !quote) { + in_comment = 1; + *e_lab++ = *buf_ptr++; + com_start = e_lab - s_lab - 2; + } + break; + case '"': + if (quote == '"') + quote = 0; + break; + case '\'': + if (quote == '\'') + quote = 0; + break; + case '*': + if (*buf_ptr == '/' && in_comment) { + in_comment = 0; + *e_lab++ = *buf_ptr++; + com_end = e_lab - s_lab; + } + break; + } + } + + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on + * preprocessor line */ + if (sc_end == 0) /* if this is the first comment, we + * must set up the buffer */ + sc_end = &(save_com[0]); + else { + *sc_end++ = '\n'; /* add newline between + * comments */ + *sc_end++ = ' '; + --line_no; + } + bcopy(s_lab + com_start, sc_end, com_end - com_start); + sc_end += com_end - com_start; + if (sc_end >= &save_com[sc_size]) + abort(); + e_lab = s_lab + com_start; + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + bp_save = buf_ptr; /* save current input buffer */ + be_save = buf_end; + buf_ptr = save_com; /* fix so that subsequent calls to + * lexi will take tokens out of + * save_com */ + *sc_end++ = ' '; /* add trailing blank, just in case */ + buf_end = sc_end; + sc_end = 0; + } + *e_lab = '\0'; /* null terminate line */ + ps.pcase = false; + } + + if (strncmp(s_lab, "#if", 3) == 0) { + if (blanklines_around_conditional_compilation) { + register c; + prefix_blankline_requested++; + while ((c = getc(input)) == '\n'); + ungetc(c, input); + } + if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) { + match_state[ifdef_level].tos = -1; + state_stack[ifdef_level++] = ps; + } + else + diag(1, "#if stack overflow"); + } + else if (strncmp(s_lab, "#else", 5) == 0) + if (ifdef_level <= 0) + diag(1, "Unmatched #else"); + else { + match_state[ifdef_level - 1] = ps; + ps = state_stack[ifdef_level - 1]; + } + else if (strncmp(s_lab, "#endif", 6) == 0) { + if (ifdef_level <= 0) + diag(1, "Unmatched #endif"); + else { + ifdef_level--; + +#ifdef undef + /* + * This match needs to be more intelligent before the + * message is useful + */ + if (match_state[ifdef_level].tos >= 0 + && bcmp(&ps, &match_state[ifdef_level], sizeof ps)) + diag(0, "Syntactically inconsistant #ifdef alternatives."); +#endif + } + if (blanklines_around_conditional_compilation) { + postfix_blankline_requested++; + n_real_blanklines = 0; + } + } + break; /* subsequent processing of the newline + * character will cause the line to be printed */ + + case comment: /* we have gotten a /* this is a biggie */ + if (flushed_nl) { /* we should force a broken line here */ + flushed_nl = false; + dump_line(); + ps.want_blank = false; /* dont insert blank at line start */ + force_nl = false; + } + pr_comment(); + break; + } /* end of big switch stmt */ + + *e_code = '\0'; /* make sure code section is null terminated */ + if (type_code != comment && type_code != newline && type_code != preesc) + ps.last_token = type_code; + } /* end of main while (1) loop */ +} + +/* + * copy input file to backup file if in_name is /blah/blah/blah/file, then + * backup file will be ".Bfile" then make the backup file the input and + * original input file the output + */ +bakcopy() +{ + int n, + bakchn; + char buff[8 * 1024]; + register char *p; + + /* construct file name .Bfile */ + for (p = in_name; *p; p++); /* skip to end of string */ + while (p > in_name && *p != '/') /* find last '/' */ + p--; + if (*p == '/') + p++; + sprintf(bakfile, "%s.BAK", p); + + /* copy in_name to backup file */ + bakchn = creat(bakfile, 0600); + if (bakchn < 0) + err(bakfile); + while (n = read(fileno(input), buff, sizeof buff)) + if (write(bakchn, buff, n) != n) + err(bakfile); + if (n < 0) + err(in_name); + close(bakchn); + fclose(input); + + /* re-open backup file as the input file */ + input = fopen(bakfile, "r"); + if (input == 0) + err(bakfile); + /* now the original input file will be the output */ + output = fopen(in_name, "w"); + if (output == 0) { + unlink(bakfile); + err(in_name); + } +} + +err(msg) + char *msg; +{ + extern int errno; + char *strerror(); + + (void)fprintf(stderr, "indent: %s: %s\n", msg, strerror(errno)); + exit(1); +} diff --git a/usr.bin/indent/indent_codes.h b/usr.bin/indent/indent_codes.h new file mode 100644 index 0000000..8373d4e --- /dev/null +++ b/usr.bin/indent/indent_codes.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)indent_codes.h 8.1 (Berkeley) 6/6/93 + */ + +#define newline 1 +#define lparen 2 +#define rparen 3 +#define unary_op 4 +#define binary_op 5 +#define postop 6 +#define question 7 +#define casestmt 8 +#define colon 9 +#define semicolon 10 +#define lbrace 11 +#define rbrace 12 +#define ident 13 +#define comma 14 +#define comment 15 +#define swstmt 16 +#define preesc 17 +#define form_feed 18 +#define decl 19 +#define sp_paren 20 +#define sp_nparen 21 +#define ifstmt 22 +#define whilestmt 23 +#define forstmt 24 +#define stmt 25 +#define stmtl 26 +#define elselit 27 +#define dolit 28 +#define dohead 29 +#define ifhead 30 +#define elsehead 31 +#define period 32 diff --git a/usr.bin/indent/indent_globs.h b/usr.bin/indent/indent_globs.h new file mode 100644 index 0000000..8f911ec --- /dev/null +++ b/usr.bin/indent/indent_globs.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)indent_globs.h 8.1 (Berkeley) 6/6/93 + */ + +#define BACKSLASH '\\' +#define bufsize 200 /* size of internal buffers */ +#define sc_size 5000 /* size of save_com buffer */ +#define label_offset 2 /* number of levels a label is placed to left + * of code */ + +#define tabsize 8 /* the size of a tab */ +#define tabmask 0177770 /* mask used when figuring length of lines + * with tabs */ + + +#define false 0 +#define true 1 + + +FILE *input; /* the fid for the input file */ +FILE *output; /* the output file */ + +#define CHECK_SIZE_CODE \ + if (e_code >= l_code) { \ + register nsize = l_code-s_code+400; \ + codebuf = (char *) realloc(codebuf, nsize); \ + e_code = codebuf + (e_code-s_code) + 1; \ + l_code = codebuf + nsize - 5; \ + s_code = codebuf + 1; \ + } +#define CHECK_SIZE_COM \ + if (e_com >= l_com) { \ + register nsize = l_com-s_com+400; \ + combuf = (char *) realloc(combuf, nsize); \ + e_com = combuf + (e_com-s_com) + 1; \ + l_com = combuf + nsize - 5; \ + s_com = combuf + 1; \ + } +#define CHECK_SIZE_LAB \ + if (e_lab >= l_lab) { \ + register nsize = l_lab-s_lab+400; \ + labbuf = (char *) realloc(labbuf, nsize); \ + e_lab = labbuf + (e_lab-s_lab) + 1; \ + l_lab = labbuf + nsize - 5; \ + s_lab = labbuf + 1; \ + } +#define CHECK_SIZE_TOKEN \ + if (e_token >= l_token) { \ + register nsize = l_token-s_token+400; \ + tokenbuf = (char *) realloc(tokenbuf, nsize); \ + e_token = tokenbuf + (e_token-s_token) + 1; \ + l_token = tokenbuf + nsize - 5; \ + s_token = tokenbuf + 1; \ + } + +char *labbuf; /* buffer for label */ +char *s_lab; /* start ... */ +char *e_lab; /* .. and end of stored label */ +char *l_lab; /* limit of label buffer */ + +char *codebuf; /* buffer for code section */ +char *s_code; /* start ... */ +char *e_code; /* .. and end of stored code */ +char *l_code; /* limit of code section */ + +char *combuf; /* buffer for comments */ +char *s_com; /* start ... */ +char *e_com; /* ... and end of stored comments */ +char *l_com; /* limit of comment buffer */ + +#define token s_token +char *tokenbuf; /* the last token scanned */ +char *s_token; +char *e_token; +char *l_token; + +char *in_buffer; /* input buffer */ +char *in_buffer_limit; /* the end of the input buffer */ +char *buf_ptr; /* ptr to next character to be taken from + * in_buffer */ +char *buf_end; /* ptr to first after last char in in_buffer */ + +char save_com[sc_size]; /* input text is saved here when looking for + * the brace after an if, while, etc */ +char *sc_end; /* pointer into save_com buffer */ + +char *bp_save; /* saved value of buf_ptr when taking input + * from save_com */ +char *be_save; /* similarly saved value of buf_end */ + + +int pointer_as_binop; +int blanklines_after_declarations; +int blanklines_before_blockcomments; +int blanklines_after_procs; +int blanklines_around_conditional_compilation; +int swallow_optional_blanklines; +int n_real_blanklines; +int prefix_blankline_requested; +int postfix_blankline_requested; +int break_comma; /* when true and not in parens, break after a + * comma */ +int btype_2; /* when true, brace should be on same line as + * if, while, etc */ +float case_ind; /* indentation level to be used for a "case + * n:" */ +int code_lines; /* count of lines with code */ +int had_eof; /* set to true when input is exhausted */ +int line_no; /* the current line number. */ +int max_col; /* the maximum allowable line length */ +int verbose; /* when true, non-essential error messages are + * printed */ +int cuddle_else; /* true if else should cuddle up to '}' */ +int star_comment_cont; /* true iff comment continuation lines should + * have stars at the beginning of each line. */ +int comment_delimiter_on_blankline; +int troff; /* true iff were generating troff input */ +int procnames_start_line; /* if true, the names of procedures + * being defined get placed in column + * 1 (ie. a newline is placed between + * the type of the procedure and its + * name) */ +int proc_calls_space; /* If true, procedure calls look like: + * foo(bar) rather than foo (bar) */ +int format_col1_comments; /* If comments which start in column 1 + * are to be magically reformatted + * (just like comments that begin in + * later columns) */ +int inhibit_formatting; /* true if INDENT OFF is in effect */ +int suppress_blanklines;/* set iff following blanklines should be + * suppressed */ +int continuation_indent;/* set to the indentation between the edge of + * code and continuation lines */ +int lineup_to_parens; /* if true, continued code within parens will + * be lined up to the open paren */ +int Bill_Shannon; /* true iff a blank should always be inserted + * after sizeof */ +int blanklines_after_declarations_at_proctop; /* This is vaguely + * similar to + * blanklines_after_decla + * rations except that + * it only applies to + * the first set of + * declarations in a + * procedure (just after + * the first '{') and it + * causes a blank line + * to be generated even + * if there are no + * declarations */ +int block_comment_max_col; +int extra_expression_indent; /* True if continuation lines from the + * expression part of "if(e)", + * "while(e)", "for(e;e;e)" should be + * indented an extra tab stop so that + * they don't conflict with the code + * that follows */ + +/* -troff font state information */ + +struct fstate { + char font[4]; + char size; + int allcaps:1; +}; +char *chfont(); + +struct fstate + keywordf, /* keyword font */ + stringf, /* string font */ + boxcomf, /* Box comment font */ + blkcomf, /* Block comment font */ + scomf, /* Same line comment font */ + bodyf; /* major body font */ + + +#define STACKSIZE 150 + +struct parser_state { + int last_token; + struct fstate cfont; /* Current font */ + int p_stack[STACKSIZE]; /* this is the parsers stack */ + int il[STACKSIZE]; /* this stack stores indentation levels */ + float cstk[STACKSIZE];/* used to store case stmt indentation levels */ + int box_com; /* set to true when we are in a "boxed" + * comment. In that case, the first non-blank + * char should be lined up with the / in /* */ + int comment_delta, + n_comment_delta; + int cast_mask; /* indicates which close parens close off + * casts */ + int sizeof_mask; /* indicates which close parens close off + * sizeof''s */ + int block_init; /* true iff inside a block initialization */ + int block_init_level; /* The level of brace nesting in an + * initialization */ + int last_nl; /* this is true if the last thing scanned was + * a newline */ + int in_or_st; /* Will be true iff there has been a + * declarator (e.g. int or char) and no left + * paren since the last semicolon. When true, + * a '{' is starting a structure definition or + * an initialization list */ + int bl_line; /* set to 1 by dump_line if the line is blank */ + int col_1; /* set to true if the last token started in + * column 1 */ + int com_col; /* this is the column in which the current + * coment should start */ + int com_ind; /* the column in which comments to the right + * of code should start */ + int com_lines; /* the number of lines with comments, set by + * dump_line */ + int dec_nest; /* current nesting level for structure or init */ + int decl_com_ind; /* the column in which comments after + * declarations should be put */ + int decl_on_line; /* set to true if this line of code has part + * of a declaration on it */ + int i_l_follow; /* the level to which ind_level should be set + * after the current line is printed */ + int in_decl; /* set to true when we are in a declaration + * stmt. The processing of braces is then + * slightly different */ + int in_stmt; /* set to 1 while in a stmt */ + int ind_level; /* the current indentation level */ + int ind_size; /* the size of one indentation level */ + int ind_stmt; /* set to 1 if next line should have an extra + * indentation level because we are in the + * middle of a stmt */ + int last_u_d; /* set to true after scanning a token which + * forces a following operator to be unary */ + int leave_comma; /* if true, never break declarations after + * commas */ + int ljust_decl; /* true if declarations should be left + * justified */ + int out_coms; /* the number of comments processed, set by + * pr_comment */ + int out_lines; /* the number of lines written, set by + * dump_line */ + int p_l_follow; /* used to remember how to indent following + * statement */ + int paren_level; /* parenthesization level. used to indent + * within stmts */ + short paren_indents[20]; /* column positions of each paren */ + int pcase; /* set to 1 if the current line label is a + * case. It is printed differently from a + * regular label */ + int search_brace; /* set to true by parse when it is necessary + * to buffer up all info up to the start of a + * stmt after an if, while, etc */ + int unindent_displace; /* comments not to the right of code + * will be placed this many + * indentation levels to the left of + * code */ + int use_ff; /* set to one if the current line should be + * terminated with a form feed */ + int want_blank; /* set to true when the following token should + * be prefixed by a blank. (Said prefixing is + * ignored in some cases.) */ + int else_if; /* True iff else if pairs should be handled + * specially */ + int decl_indent; /* column to indent declared identifiers to */ + int its_a_keyword; + int sizeof_keyword; + int dumped_decl_indent; + float case_indent; /* The distance to indent case labels from the + * switch statement */ + int in_parameter_declaration; + int indent_parameters; + int tos; /* pointer to top of stack */ + char procname[100]; /* The name of the current procedure */ + int just_saw_decl; +} ps; + +int ifdef_level; +int rparen_count; +struct parser_state state_stack[5]; +struct parser_state match_state[5]; diff --git a/usr.bin/indent/io.c b/usr.bin/indent/io.c new file mode 100644 index 0000000..4615db2 --- /dev/null +++ b/usr.bin/indent/io.c @@ -0,0 +1,625 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)io.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "indent_globs.h" + + +int comment_open; +static paren_target; + +dump_line() +{ /* dump_line is the routine that actually + * effects the printing of the new source. It + * prints the label section, followed by the + * code section with the appropriate nesting + * level, followed by any comments */ + register int cur_col, + target_col; + static not_first_line; + + if (ps.procname[0]) { + if (troff) { + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + fprintf(output, ".Pr \"%s\"\n", ps.procname); + } + ps.ind_level = 0; + ps.procname[0] = 0; + } + if (s_code == e_code && s_lab == e_lab && s_com == e_com) { + if (suppress_blanklines > 0) + suppress_blanklines--; + else { + ps.bl_line = true; + n_real_blanklines++; + } + } + else if (!inhibit_formatting) { + suppress_blanklines = 0; + ps.bl_line = false; + if (prefix_blankline_requested && not_first_line) + if (swallow_optional_blanklines) { + if (n_real_blanklines == 1) + n_real_blanklines = 0; + } + else { + if (n_real_blanklines == 0) + n_real_blanklines = 1; + } + while (--n_real_blanklines >= 0) + putc('\n', output); + n_real_blanklines = 0; + if (ps.ind_level == 0) + ps.ind_stmt = 0; /* this is a class A kludge. dont do + * additional statement indentation if we are + * at bracket level 0 */ + + if (e_lab != s_lab || e_code != s_code) + ++code_lines; /* keep count of lines with code */ + + + if (e_lab != s_lab) { /* print lab, if any */ + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + cur_col = pad_output(1, compute_label_target()); + if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0 + || strncmp(s_lab, "#endif", 6) == 0)) { + register char *s = s_lab; + if (e_lab[-1] == '\n') e_lab--; + do putc(*s++, output); + while (s < e_lab && 'a' <= *s && *s<='z'); + while ((*s == ' ' || *s == '\t') && s < e_lab) + s++; + if (s < e_lab) + fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */", + e_lab - s, s); + } + else fprintf(output, "%.*s", e_lab - s_lab, s_lab); + cur_col = count_spaces(cur_col, s_lab); + } + else + cur_col = 1; /* there is no label section */ + + ps.pcase = false; + + if (s_code != e_code) { /* print code section, if any */ + register char *p; + + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + target_col = compute_code_target(); + { + register i; + + for (i = 0; i < ps.p_l_follow; i++) + if (ps.paren_indents[i] >= 0) + ps.paren_indents[i] = -(ps.paren_indents[i] + target_col); + } + cur_col = pad_output(cur_col, target_col); + for (p = s_code; p < e_code; p++) + if (*p == (char) 0200) + fprintf(output, "%d", target_col * 7); + else + putc(*p, output); + cur_col = count_spaces(cur_col, s_code); + } + if (s_com != e_com) + if (troff) { + int all_here = 0; + register char *p; + + if (e_com[-1] == '/' && e_com[-2] == '*') + e_com -= 2, all_here++; + while (e_com > s_com && e_com[-1] == ' ') + e_com--; + *e_com = 0; + p = s_com; + while (*p == ' ') + p++; + if (p[0] == '/' && p[1] == '*') + p += 2, all_here++; + else if (p[0] == '*') + p += p[1] == '/' ? 2 : 1; + while (*p == ' ') + p++; + if (*p == 0) + goto inhibit_newline; + if (comment_open < 2 && ps.box_com) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + if (comment_open == 0) { + if ('a' <= *p && *p <= 'z') + *p = *p + 'A' - 'a'; + if (e_com - p < 50 && all_here == 2) { + register char *follow = p; + fprintf(output, "\n.nr C! \\w\1"); + while (follow < e_com) { + switch (*follow) { + case '\n': + putc(' ', output); + case 1: + break; + case '\\': + putc('\\', output); + default: + putc(*follow, output); + } + follow++; + } + putc(1, output); + } + fprintf(output, "\n./* %dp %d %dp\n", + ps.com_col * 7, + (s_code != e_code || s_lab != e_lab) - ps.box_com, + target_col * 7); + } + comment_open = 1 + ps.box_com; + while (*p) { + if (*p == BACKSLASH) + putc(BACKSLASH, output); + putc(*p++, output); + } + } + else { /* print comment, if any */ + register target = ps.com_col; + register char *com_st = s_com; + + target += ps.comment_delta; + while (*com_st == '\t') + com_st++, target += 8; /* ? */ + while (target <= 0) + if (*com_st == ' ') + target++, com_st++; + else if (*com_st == '\t') + target = ((target - 1) & ~7) + 9, com_st++; + else + target = 1; + if (cur_col > target) { /* if comment cant fit on this line, + * put it on next line */ + putc('\n', output); + cur_col = 1; + ++ps.out_lines; + } + while (e_com > com_st && isspace(e_com[-1])) + e_com--; + cur_col = pad_output(cur_col, target); + if (!ps.box_com) { + if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) + if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1) + com_st[1] = '*'; + else + fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output); + } + fwrite(com_st, e_com - com_st, 1, output); + ps.comment_delta = ps.n_comment_delta; + cur_col = count_spaces(cur_col, com_st); + ++ps.com_lines; /* count lines with comments */ + } + if (ps.use_ff) + putc('\014', output); + else + putc('\n', output); +inhibit_newline: + ++ps.out_lines; + if (ps.just_saw_decl == 1 && blanklines_after_declarations) { + prefix_blankline_requested = 1; + ps.just_saw_decl = 0; + } + else + prefix_blankline_requested = postfix_blankline_requested; + postfix_blankline_requested = 0; + } + ps.decl_on_line = ps.in_decl; /* if we are in the middle of a + * declaration, remember that fact for + * proper comment indentation */ + ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be + * indented if we have not + * completed this stmt and if + * we are not in the middle of + * a declaration */ + ps.use_ff = false; + ps.dumped_decl_indent = 0; + *(e_lab = s_lab) = '\0'; /* reset buffers */ + *(e_code = s_code) = '\0'; + *(e_com = s_com) = '\0'; + ps.ind_level = ps.i_l_follow; + ps.paren_level = ps.p_l_follow; + paren_target = -ps.paren_indents[ps.paren_level - 1]; + not_first_line = 1; + return; +} + +compute_code_target() +{ + register target_col = ps.ind_size * ps.ind_level + 1; + + if (ps.paren_level) + if (!lineup_to_parens) + target_col += continuation_indent * ps.paren_level; + else { + register w; + register t = paren_target; + + if ((w = count_spaces(t, s_code) - max_col) > 0 + && count_spaces(target_col, s_code) <= max_col) { + t -= w + 1; + if (t > target_col) + target_col = t; + } + else + target_col = t; + } + else if (ps.ind_stmt) + target_col += continuation_indent; + return target_col; +} + +compute_label_target() +{ + return + ps.pcase ? (int) (case_ind * ps.ind_size) + 1 + : *s_lab == '#' ? 1 + : ps.ind_size * (ps.ind_level - label_offset) + 1; +} + + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: fill_buffer + * + * FUNCTION: Reads one block of input into input_buffer + * + * HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A + * Willcox of CAC Added check for switch back to partly full input + * buffer from temporary buffer + * + */ +int +fill_buffer() +{ /* this routine reads stuff from the input */ + register char *p; + register int i; + register FILE *f = input; + + if (bp_save != 0) { /* there is a partly filled input buffer left */ + buf_ptr = bp_save; /* dont read anything, just switch buffers */ + buf_end = be_save; + bp_save = be_save = 0; + if (buf_ptr < buf_end) + return; /* only return if there is really something in + * this buffer */ + } + for (p = in_buffer;;) { + if (p >= in_buffer_limit) { + register size = (in_buffer_limit - in_buffer) * 2 + 10; + register offset = p - in_buffer; + in_buffer = (char *) realloc(in_buffer, size); + if (in_buffer == 0) + err("input line too long"); + p = in_buffer + offset; + in_buffer_limit = in_buffer + size - 2; + } + if ((i = getc(f)) == EOF) { + *p++ = ' '; + *p++ = '\n'; + had_eof = true; + break; + } + *p++ = i; + if (i == '\n') + break; + } + buf_ptr = in_buffer; + buf_end = p; + if (p[-2] == '/' && p[-3] == '*') { + if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0) + fill_buffer(); /* flush indent error message */ + else { + int com = 0; + + p = in_buffer; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '/' && p[1] == '*') { + p += 2; + while (*p == ' ' || *p == '\t') + p++; + if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E' + && p[4] == 'N' && p[5] == 'T') { + p += 6; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '*') + com = 1; + else if (*p == 'O') + if (*++p == 'N') + p++, com = 1; + else if (*p == 'F' && *++p == 'F') + p++, com = 2; + while (*p == ' ' || *p == '\t') + p++; + if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) { + if (s_com != e_com || s_lab != e_lab || s_code != e_code) + dump_line(); + if (!(inhibit_formatting = com - 1)) { + n_real_blanklines = 0; + postfix_blankline_requested = 0; + prefix_blankline_requested = 0; + suppress_blanklines = 1; + } + } + } + } + } + } + if (inhibit_formatting) { + p = in_buffer; + do + putc(*p, output); + while (*p++ != '\n'); + } + return; +} + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: pad_output + * + * FUNCTION: Writes tabs and spaces to move the current column up to the desired + * position. + * + * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf. + * + * PARAMETERS: current integer The current column target + * nteger The desired column + * + * RETURNS: Integer value of the new column. (If current >= target, no action is + * taken, and current is returned. + * + * GLOBALS: None + * + * CALLS: write (sys) + * + * CALLED BY: dump_line + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +pad_output(current, target) /* writes tabs and blanks (if necessary) to + * get the current output position up to the + * target column */ + int current; /* the current column value */ + int target; /* position we want it at */ +{ + register int curr; /* internal column pointer */ + register int tcur; + + if (troff) + fprintf(output, "\\h'|%dp'", (target - 1) * 7); + else { + if (current >= target) + return (current); /* line is already long enough */ + curr = current; + while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) { + putc('\t', output); + curr = tcur; + } + while (curr++ < target) + putc(' ', output); /* pad with final blanks */ + } + return (target); +} + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: count_spaces + * + * FUNCTION: Find out where printing of a given string will leave the current + * character position on output. + * + * ALGORITHM: Run thru input string and add appropriate values to current + * position. + * + * RETURNS: Integer value of position after printing "buffer" starting in column + * "current". + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +int +count_spaces(current, buffer) +/* + * this routine figures out where the character position will be after + * printing the text in buffer starting at column "current" + */ + int current; + char *buffer; +{ + register char *buf; /* used to look thru buffer */ + register int cur; /* current character counter */ + + cur = current; + + for (buf = buffer; *buf != '\0'; ++buf) { + switch (*buf) { + + case '\n': + case 014: /* form feed */ + cur = 1; + break; + + case '\t': + cur = ((cur - 1) & tabmask) + tabsize + 1; + break; + + case 010: /* backspace */ + --cur; + break; + + default: + ++cur; + break; + } /* end of switch */ + } /* end of for loop */ + return (cur); +} + +int found_err; +/* VARARGS2 */ +diag(level, msg, a, b) + char *msg; +{ + if (level) + found_err = 1; + if (output == stdout) { + fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); + fprintf(stdout, msg, a, b); + fprintf(stdout, " */\n"); + } + else { + fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); + fprintf(stderr, msg, a, b); + fprintf(stderr, "\n"); + } +} + +writefdef(f, nm) + register struct fstate *f; +{ + fprintf(output, ".ds f%c %s\n.nr s%c %d\n", + nm, f->font, nm, f->size); +} + +char * +chfont(of, nf, s) + register struct fstate *of, + *nf; + char *s; +{ + if (of->font[0] != nf->font[0] + || of->font[1] != nf->font[1]) { + *s++ = '\\'; + *s++ = 'f'; + if (nf->font[1]) { + *s++ = '('; + *s++ = nf->font[0]; + *s++ = nf->font[1]; + } + else + *s++ = nf->font[0]; + } + if (nf->size != of->size) { + *s++ = '\\'; + *s++ = 's'; + if (nf->size < of->size) { + *s++ = '-'; + *s++ = '0' + of->size - nf->size; + } + else { + *s++ = '+'; + *s++ = '0' + nf->size - of->size; + } + } + return s; +} + + +parsefont(f, s0) + register struct fstate *f; + char *s0; +{ + register char *s = s0; + int sizedelta = 0; + bzero(f, sizeof *f); + while (*s) { + if (isdigit(*s)) + f->size = f->size * 10 + *s - '0'; + else if (isupper(*s)) + if (f->font[0]) + f->font[1] = *s; + else + f->font[0] = *s; + else if (*s == 'c') + f->allcaps = 1; + else if (*s == '+') + sizedelta++; + else if (*s == '-') + sizedelta--; + else { + fprintf(stderr, "indent: bad font specification: %s\n", s0); + exit(1); + } + s++; + } + if (f->font[0] == 0) + f->font[0] = 'R'; + if (bodyf.size == 0) + bodyf.size = 11; + if (f->size == 0) + f->size = bodyf.size + sizedelta; + else if (sizedelta > 0) + f->size += bodyf.size; + else + f->size = bodyf.size - f->size; +} diff --git a/usr.bin/indent/lexi.c b/usr.bin/indent/lexi.c new file mode 100644 index 0000000..8da9d2c --- /dev/null +++ b/usr.bin/indent/lexi.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lexi.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Here we have the token scanner for indent. It scans off one token and puts + * it in the global variable "token". It returns a code, indicating the type + * of token scanned. + */ + +#include +#include +#include +#include +#include "indent_globs.h" +#include "indent_codes.h" + +#define alphanum 1 +#define opchar 3 + +struct templ { + char *rwd; + int rwcode; +}; + +struct templ specials[100] = +{ + "switch", 1, + "case", 2, + "break", 0, + "struct", 3, + "union", 3, + "enum", 3, + "default", 2, + "int", 4, + "char", 4, + "float", 4, + "double", 4, + "long", 4, + "short", 4, + "typdef", 4, + "unsigned", 4, + "register", 4, + "static", 4, + "global", 4, + "extern", 4, + "void", 4, + "goto", 0, + "return", 0, + "if", 5, + "while", 5, + "for", 5, + "else", 6, + "do", 6, + "sizeof", 7, + 0, 0 +}; + +char chartype[128] = +{ /* this is used to facilitate the decision of + * what type (alphanumeric, operator) each + * character is */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 0, 0, 1, 3, 3, 0, + 0, 0, 3, 3, 0, 3, 0, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 3, 3, 3, 3, + 0, 1, 1, 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, 0, 0, 3, 1, + 0, 1, 1, 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, 3, 0, 3, 0 +}; + + + + +int +lexi() +{ + int unary_delim; /* this is set to 1 if the current token + * + * forces a following operator to be unary */ + static int last_code; /* the last token type returned */ + static int l_struct; /* set to 1 if the last token was 'struct' */ + int code; /* internal code to be returned */ + char qchar; /* the delimiter character for a string */ + + e_token = s_token; /* point to start of place to save token */ + unary_delim = false; + ps.col_1 = ps.last_nl; /* tell world that this token started in + * column 1 iff the last thing scanned was nl */ + ps.last_nl = false; + + while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ + ps.col_1 = false; /* leading blanks imply token is not in column + * 1 */ + if (++buf_ptr >= buf_end) + fill_buffer(); + } + + /* Scan an alphanumeric token */ + if (chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) { + /* + * we have a character or number + */ + register char *j; /* used for searching thru list of + * + * reserved words */ + register struct templ *p; + + if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) { + int seendot = 0, + seenexp = 0; + if (*buf_ptr == '0' && + (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) { + *e_token++ = *buf_ptr++; + *e_token++ = *buf_ptr++; + while (isxdigit(*buf_ptr)) { + CHECK_SIZE_TOKEN; + *e_token++ = *buf_ptr++; + } + } + else + while (1) { + if (*buf_ptr == '.') + if (seendot) + break; + else + seendot++; + CHECK_SIZE_TOKEN; + *e_token++ = *buf_ptr++; + if (!isdigit(*buf_ptr) && *buf_ptr != '.') + if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp) + break; + else { + seenexp++; + seendot++; + CHECK_SIZE_TOKEN; + *e_token++ = *buf_ptr++; + if (*buf_ptr == '+' || *buf_ptr == '-') + *e_token++ = *buf_ptr++; + } + } + if (*buf_ptr == 'L' || *buf_ptr == 'l') + *e_token++ = *buf_ptr++; + } + else + while (chartype[*buf_ptr] == alphanum) { /* copy it over */ + CHECK_SIZE_TOKEN; + *e_token++ = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + } + *e_token++ = '\0'; + while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ + if (++buf_ptr >= buf_end) + fill_buffer(); + } + ps.its_a_keyword = false; + ps.sizeof_keyword = false; + if (l_struct) { /* if last token was 'struct', then this token + * should be treated as a declaration */ + l_struct = false; + last_code = ident; + ps.last_u_d = true; + return (decl); + } + ps.last_u_d = false; /* Operator after indentifier is binary */ + last_code = ident; /* Remember that this is the code we will + * return */ + + /* + * This loop will check if the token is a keyword. + */ + for (p = specials; (j = p->rwd) != 0; p++) { + register char *p = s_token; /* point at scanned token */ + if (*j++ != *p++ || *j++ != *p++) + continue; /* This test depends on the fact that + * identifiers are always at least 1 character + * long (ie. the first two bytes of the + * identifier are always meaningful) */ + if (p[-1] == 0) + break; /* If its a one-character identifier */ + while (*p++ == *j) + if (*j++ == 0) + goto found_keyword; /* I wish that C had a multi-level + * break... */ + } + if (p->rwd) { /* we have a keyword */ + found_keyword: + ps.its_a_keyword = true; + ps.last_u_d = true; + switch (p->rwcode) { + case 1: /* it is a switch */ + return (swstmt); + case 2: /* a case or default */ + return (casestmt); + + case 3: /* a "struct" */ + if (ps.p_l_follow) + break; /* inside parens: cast */ + l_struct = true; + + /* + * Next time around, we will want to know that we have had a + * 'struct' + */ + case 4: /* one of the declaration keywords */ + if (ps.p_l_follow) { + ps.cast_mask |= 1 << ps.p_l_follow; + break; /* inside parens: cast */ + } + last_code = decl; + return (decl); + + case 5: /* if, while, for */ + return (sp_paren); + + case 6: /* do, else */ + return (sp_nparen); + + case 7: + ps.sizeof_keyword = true; + default: /* all others are treated like any other + * identifier */ + return (ident); + } /* end of switch */ + } /* end of if (found_it) */ + if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) { + register char *tp = buf_ptr; + while (tp < buf_end) + if (*tp++ == ')' && (*tp == ';' || *tp == ',')) + goto not_proc; + strncpy(ps.procname, token, sizeof ps.procname - 1); + ps.in_parameter_declaration = 1; + rparen_count = 1; + not_proc:; + } + /* + * The following hack attempts to guess whether or not the current + * token is in fact a declaration keyword -- one that has been + * typedefd + */ + if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_') + && !ps.p_l_follow + && !ps.block_init + && (ps.last_token == rparen || ps.last_token == semicolon || + ps.last_token == decl || + ps.last_token == lbrace || ps.last_token == rbrace)) { + ps.its_a_keyword = true; + ps.last_u_d = true; + last_code = decl; + return decl; + } + if (last_code == decl) /* if this is a declared variable, then + * following sign is unary */ + ps.last_u_d = true; /* will make "int a -1" work */ + last_code = ident; + return (ident); /* the ident is not in the list */ + } /* end of procesing for alpanum character */ + + /* Scan a non-alphanumeric token */ + + *e_token++ = *buf_ptr; /* if it is only a one-character token, it is + * moved here */ + *e_token = '\0'; + if (++buf_ptr >= buf_end) + fill_buffer(); + + switch (*token) { + case '\n': + unary_delim = ps.last_u_d; + ps.last_nl = true; /* remember that we just had a newline */ + code = (had_eof ? 0 : newline); + + /* + * if data has been exausted, the newline is a dummy, and we should + * return code to stop + */ + break; + + case '\'': /* start of quoted character */ + case '"': /* start of string */ + qchar = *token; + if (troff) { + e_token[-1] = '`'; + if (qchar == '"') + *e_token++ = '`'; + e_token = chfont(&bodyf, &stringf, e_token); + } + do { /* copy the string */ + while (1) { /* move one character or [/] */ + if (*buf_ptr == '\n') { + printf("%d: Unterminated literal\n", line_no); + goto stop_lit; + } + CHECK_SIZE_TOKEN; /* Only have to do this once in this loop, + * since CHECK_SIZE guarantees that there + * are at least 5 entries left */ + *e_token = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + if (*e_token == BACKSLASH) { /* if escape, copy extra char */ + if (*buf_ptr == '\n') /* check for escaped newline */ + ++line_no; + if (troff) { + *++e_token = BACKSLASH; + if (*buf_ptr == BACKSLASH) + *++e_token = BACKSLASH; + } + *++e_token = *buf_ptr++; + ++e_token; /* we must increment this again because we + * copied two chars */ + if (buf_ptr >= buf_end) + fill_buffer(); + } + else + break; /* we copied one character */ + } /* end of while (1) */ + } while (*e_token++ != qchar); + if (troff) { + e_token = chfont(&stringf, &bodyf, e_token - 1); + if (qchar == '"') + *e_token++ = '\''; + } +stop_lit: + code = ident; + break; + + case ('('): + case ('['): + unary_delim = true; + code = lparen; + break; + + case (')'): + case (']'): + code = rparen; + break; + + case '#': + unary_delim = ps.last_u_d; + code = preesc; + break; + + case '?': + unary_delim = true; + code = question; + break; + + case (':'): + code = colon; + unary_delim = true; + break; + + case (';'): + unary_delim = true; + code = semicolon; + break; + + case ('{'): + unary_delim = true; + + /* + * if (ps.in_or_st) ps.block_init = 1; + */ + /* ? code = ps.block_init ? lparen : lbrace; */ + code = lbrace; + break; + + case ('}'): + unary_delim = true; + /* ? code = ps.block_init ? rparen : rbrace; */ + code = rbrace; + break; + + case 014: /* a form feed */ + unary_delim = ps.last_u_d; + ps.last_nl = true; /* remember this so we can set 'ps.col_1' + * right */ + code = form_feed; + break; + + case (','): + unary_delim = true; + code = comma; + break; + + case '.': + unary_delim = false; + code = period; + break; + + case '-': + case '+': /* check for -, +, --, ++ */ + code = (ps.last_u_d ? unary_op : binary_op); + unary_delim = true; + + if (*buf_ptr == token[0]) { + /* check for doubled character */ + *e_token++ = *buf_ptr++; + /* buffer overflow will be checked at end of loop */ + if (last_code == ident || last_code == rparen) { + code = (ps.last_u_d ? unary_op : postop); + /* check for following ++ or -- */ + unary_delim = false; + } + } + else if (*buf_ptr == '=') + /* check for operator += */ + *e_token++ = *buf_ptr++; + else if (*buf_ptr == '>') { + /* check for operator -> */ + *e_token++ = *buf_ptr++; + if (!pointer_as_binop) { + unary_delim = false; + code = unary_op; + ps.want_blank = false; + } + } + break; /* buffer overflow will be checked at end of + * switch */ + + case '=': + if (ps.in_or_st) + ps.block_init = 1; +#ifdef undef + if (chartype[*buf_ptr] == opchar) { /* we have two char assignment */ + e_token[-1] = *buf_ptr++; + if ((e_token[-1] == '<' || e_token[-1] == '>') && e_token[-1] == *buf_ptr) + *e_token++ = *buf_ptr++; + *e_token++ = '='; /* Flip =+ to += */ + *e_token = 0; + } +#else + if (*buf_ptr == '=') {/* == */ + *e_token++ = '='; /* Flip =+ to += */ + buf_ptr++; + *e_token = 0; + } +#endif + code = binary_op; + unary_delim = true; + break; + /* can drop thru!!! */ + + case '>': + case '<': + case '!': /* ops like <, <<, <=, !=, etc */ + if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') { + *e_token++ = *buf_ptr; + if (++buf_ptr >= buf_end) + fill_buffer(); + } + if (*buf_ptr == '=') + *e_token++ = *buf_ptr++; + code = (ps.last_u_d ? unary_op : binary_op); + unary_delim = true; + break; + + default: + if (token[0] == '/' && *buf_ptr == '*') { + /* it is start of comment */ + *e_token++ = '*'; + + if (++buf_ptr >= buf_end) + fill_buffer(); + + code = comment; + unary_delim = ps.last_u_d; + break; + } + while (*(e_token - 1) == *buf_ptr || *buf_ptr == '=') { + /* + * handle ||, &&, etc, and also things as in int *****i + */ + *e_token++ = *buf_ptr; + if (++buf_ptr >= buf_end) + fill_buffer(); + } + code = (ps.last_u_d ? unary_op : binary_op); + unary_delim = true; + + + } /* end of switch */ + if (code != newline) { + l_struct = false; + last_code = code; + } + if (buf_ptr >= buf_end) /* check for input buffer empty */ + fill_buffer(); + ps.last_u_d = unary_delim; + *e_token = '\0'; /* null terminate the token */ + return (code); +} + +/* + * Add the given keyword to the keyword table, using val as the keyword type + */ +addkey(key, val) + char *key; +{ + register struct templ *p = specials; + while (p->rwd) + if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) + return; + else + p++; + if (p >= specials + sizeof specials / sizeof specials[0]) + return; /* For now, table overflows are silently + * ignored */ + p->rwd = key; + p->rwcode = val; + p[1].rwd = 0; + p[1].rwcode = 0; + return; +} diff --git a/usr.bin/indent/parse.c b/usr.bin/indent/parse.c new file mode 100644 index 0000000..fef22cf --- /dev/null +++ b/usr.bin/indent/parse.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include "indent_globs.h" +#include "indent_codes.h" + +parse(tk) + int tk; /* the code for the construct scanned */ +{ + int i; + +#ifdef debug + printf("%2d - %s\n", tk, token); +#endif + + while (ps.p_stack[ps.tos] == ifhead && tk != elselit) { + /* true if we have an if without an else */ + ps.p_stack[ps.tos] = stmt; /* apply the if(..) stmt ::= stmt + * reduction */ + reduce(); /* see if this allows any reduction */ + } + + + switch (tk) { /* go on and figure out what to do with the + * input */ + + case decl: /* scanned a declaration word */ + ps.search_brace = btype_2; + /* indicate that following brace should be on same line */ + if (ps.p_stack[ps.tos] != decl) { /* only put one declaration + * onto stack */ + break_comma = true; /* while in declaration, newline should be + * forced after comma */ + ps.p_stack[++ps.tos] = decl; + ps.il[ps.tos] = ps.i_l_follow; + + if (ps.ljust_decl) {/* only do if we want left justified + * declarations */ + ps.ind_level = 0; + for (i = ps.tos - 1; i > 0; --i) + if (ps.p_stack[i] == decl) + ++ps.ind_level; /* indentation is number of + * declaration levels deep we are */ + ps.i_l_follow = ps.ind_level; + } + } + break; + + case ifstmt: /* scanned if (...) */ + if (ps.p_stack[ps.tos] == elsehead && ps.else_if) /* "else if ..." */ + ps.i_l_follow = ps.il[ps.tos]; + case dolit: /* 'do' */ + case forstmt: /* for (...) */ + ps.p_stack[++ps.tos] = tk; + ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; + ++ps.i_l_follow; /* subsequent statements should be indented 1 */ + ps.search_brace = btype_2; + break; + + case lbrace: /* scanned { */ + break_comma = false; /* don't break comma in an initial list */ + if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl + || ps.p_stack[ps.tos] == stmtl) + ++ps.i_l_follow; /* it is a random, isolated stmt group or a + * declaration */ + else { + if (s_code == e_code) { + /* + * only do this if there is nothing on the line + */ + --ps.ind_level; + /* + * it is a group as part of a while, for, etc. + */ + if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1) + --ps.ind_level; + /* + * for a switch, brace should be two levels out from the code + */ + } + } + + ps.p_stack[++ps.tos] = lbrace; + ps.il[ps.tos] = ps.ind_level; + ps.p_stack[++ps.tos] = stmt; + /* allow null stmt between braces */ + ps.il[ps.tos] = ps.i_l_follow; + break; + + case whilestmt: /* scanned while (...) */ + if (ps.p_stack[ps.tos] == dohead) { + /* it is matched with do stmt */ + ps.ind_level = ps.i_l_follow = ps.il[ps.tos]; + ps.p_stack[++ps.tos] = whilestmt; + ps.il[ps.tos] = ps.ind_level = ps.i_l_follow; + } + else { /* it is a while loop */ + ps.p_stack[++ps.tos] = whilestmt; + ps.il[ps.tos] = ps.i_l_follow; + ++ps.i_l_follow; + ps.search_brace = btype_2; + } + + break; + + case elselit: /* scanned an else */ + + if (ps.p_stack[ps.tos] != ifhead) + diag(1, "Unmatched 'else'"); + else { + ps.ind_level = ps.il[ps.tos]; /* indentation for else should + * be same as for if */ + ps.i_l_follow = ps.ind_level + 1; /* everything following should + * be in 1 level */ + ps.p_stack[ps.tos] = elsehead; + /* remember if with else */ + ps.search_brace = btype_2 | ps.else_if; + } + break; + + case rbrace: /* scanned a } */ + /* stack should have or */ + if (ps.p_stack[ps.tos - 1] == lbrace) { + ps.ind_level = ps.i_l_follow = ps.il[--ps.tos]; + ps.p_stack[ps.tos] = stmt; + } + else + diag(1, "Stmt nesting error."); + break; + + case swstmt: /* had switch (...) */ + ps.p_stack[++ps.tos] = swstmt; + ps.cstk[ps.tos] = case_ind; + /* save current case indent level */ + ps.il[ps.tos] = ps.i_l_follow; + case_ind = ps.i_l_follow + ps.case_indent; /* cases should be one + * level down from + * switch */ + ps.i_l_follow += ps.case_indent + 1; /* statements should be two + * levels in */ + ps.search_brace = btype_2; + break; + + case semicolon: /* this indicates a simple stmt */ + break_comma = false; /* turn off flag to break after commas in a + * declaration */ + ps.p_stack[++ps.tos] = stmt; + ps.il[ps.tos] = ps.ind_level; + break; + + default: /* this is an error */ + diag(1, "Unknown code to parser"); + return; + + + } /* end of switch */ + + reduce(); /* see if any reduction can be done */ + +#ifdef debug + for (i = 1; i <= ps.tos; ++i) + printf("(%d %d)", ps.p_stack[i], ps.il[i]); + printf("\n"); +#endif + + return; +} + +/* + * NAME: reduce + * + * FUNCTION: Implements the reduce part of the parsing algorithm + * + * ALGORITHM: The following reductions are done. Reductions are repeated + * until no more are possible. + * + * Old TOS New TOS + * + * + * do "dostmt" + * if "ifstmt" + * switch + * decl + * "ifelse" + * for + * while + * "dostmt" while + * + * On each reduction, ps.i_l_follow (the indentation for the following line) + * is set to the indentation level associated with the old TOS. + * + * PARAMETERS: None + * + * RETURNS: Nothing + * + * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos = + * + * CALLS: None + * + * CALLED BY: parse + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +/*----------------------------------------------*\ +| REDUCTION PHASE | +\*----------------------------------------------*/ +reduce() +{ + + register int i; + + for (;;) { /* keep looping until there is nothing left to + * reduce */ + + switch (ps.p_stack[ps.tos]) { + + case stmt: + switch (ps.p_stack[ps.tos - 1]) { + + case stmt: + case stmtl: + /* stmtl stmt or stmt stmt */ + ps.p_stack[--ps.tos] = stmtl; + break; + + case dolit: /* */ + ps.p_stack[--ps.tos] = dohead; + ps.i_l_follow = ps.il[ps.tos]; + break; + + case ifstmt: + /* */ + ps.p_stack[--ps.tos] = ifhead; + for (i = ps.tos - 1; + ( + ps.p_stack[i] != stmt + && + ps.p_stack[i] != stmtl + && + ps.p_stack[i] != lbrace + ); + --i); + ps.i_l_follow = ps.il[i]; + /* + * for the time being, we will assume that there is no else on + * this if, and set the indentation level accordingly. If an + * else is scanned, it will be fixed up later + */ + break; + + case swstmt: + /* */ + case_ind = ps.cstk[ps.tos - 1]; + + case decl: /* finish of a declaration */ + case elsehead: + /* < else> */ + case forstmt: + /* */ + case whilestmt: + /* */ + ps.p_stack[--ps.tos] = stmt; + ps.i_l_follow = ps.il[ps.tos]; + break; + + default: /* */ + return; + + } /* end of section for on top of stack */ + break; + + case whilestmt: /* while (...) on top */ + if (ps.p_stack[ps.tos - 1] == dohead) { + /* it is termination of a do while */ + ps.p_stack[--ps.tos] = stmt; + break; + } + else + return; + + default: /* anything else on top */ + return; + + } + } +} diff --git a/usr.bin/indent/pr_comment.c b/usr.bin/indent/pr_comment.c new file mode 100644 index 0000000..2d4bc90 --- /dev/null +++ b/usr.bin/indent/pr_comment.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)pr_comment.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include "indent_globs.h" + +/* + * NAME: + * pr_comment + * + * FUNCTION: + * This routine takes care of scanning and printing comments. + * + * ALGORITHM: + * 1) Decide where the comment should be aligned, and if lines should + * be broken. + * 2) If lines should not be broken and filled, just copy up to end of + * comment. + * 3) If lines should be filled, then scan thru input_buffer copying + * characters to com_buf. Remember where the last blank, tab, or + * newline was. When line is filled, print up to last blank and + * continue copying. + * + * HISTORY: + * November 1976 D A Willcox of CAC Initial coding + * 12/6/76 D A Willcox of CAC Modification to handle + * UNIX-style comments + * + */ + +/* + * this routine processes comments. It makes an attempt to keep comments from + * going over the max line length. If a line is too long, it moves everything + * from the last blank to the next comment line. Blanks and tabs from the + * beginning of the input line are removed + */ + + +pr_comment() +{ + int now_col; /* column we are in now */ + int adj_max_col; /* Adjusted max_col for when we decide to + * spill comments over the right margin */ + char *last_bl; /* points to the last blank in the output + * buffer */ + char *t_ptr; /* used for moving string */ + int unix_comment; /* tri-state variable used to decide if it is + * a unix-style comment. 0 means only blanks + * since /*, 1 means regular style comment, 2 + * means unix style comment */ + int break_delim = comment_delimiter_on_blankline; + int l_just_saw_decl = ps.just_saw_decl; + /* + * int ps.last_nl = 0; /* true iff the last significant thing + * weve seen is a newline + */ + int one_liner = 1; /* true iff this comment is a one-liner */ + adj_max_col = max_col; + ps.just_saw_decl = 0; + last_bl = 0; /* no blanks found so far */ + ps.box_com = false; /* at first, assume that we are not in + * a boxed comment or some other + * comment that should not be touched */ + ++ps.out_coms; /* keep track of number of comments */ + unix_comment = 1; /* set flag to let us figure out if there is a + * unix-style comment ** DISABLED: use 0 to + * reenable this hack! */ + + /* Figure where to align and how to treat the comment */ + + if (ps.col_1 && !format_col1_comments) { /* if comment starts in column + * 1 it should not be touched */ + ps.box_com = true; + ps.com_col = 1; + } + else { + if (*buf_ptr == '-' || *buf_ptr == '*') { + ps.box_com = true; /* a comment with a '-' or '*' immediately + * after the /* is assumed to be a boxed + * comment */ + break_delim = 0; + } + if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code)) { + /* klg: check only if this line is blank */ + /* + * If this (*and previous lines are*) blank, dont put comment way + * out at left + */ + ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1; + adj_max_col = block_comment_max_col; + if (ps.com_col <= 1) + ps.com_col = 1 + !format_col1_comments; + } + else { + register target_col; + break_delim = 0; + if (s_code != e_code) + target_col = count_spaces(compute_code_target(), s_code); + else { + target_col = 1; + if (s_lab != e_lab) + target_col = count_spaces(compute_label_target(), s_lab); + } + ps.com_col = ps.decl_on_line || ps.ind_level == 0 ? ps.decl_com_ind : ps.com_ind; + if (ps.com_col < target_col) + ps.com_col = ((target_col + 7) & ~7) + 1; + if (ps.com_col + 24 > adj_max_col) + adj_max_col = ps.com_col + 24; + } + } + if (ps.box_com) { + buf_ptr[-2] = 0; + ps.n_comment_delta = 1 - count_spaces(1, in_buffer); + buf_ptr[-2] = '/'; + } + else { + ps.n_comment_delta = 0; + while (*buf_ptr == ' ' || *buf_ptr == '\t') + buf_ptr++; + } + ps.comment_delta = 0; + *e_com++ = '/'; /* put '/*' into buffer */ + *e_com++ = '*'; + if (*buf_ptr != ' ' && !ps.box_com) + *e_com++ = ' '; + + *e_com = '\0'; + if (troff) { + now_col = 1; + adj_max_col = 80; + } + else + now_col = count_spaces(ps.com_col, s_com); /* figure what column we + * would be in if we + * printed the comment + * now */ + + /* Start to copy the comment */ + + while (1) { /* this loop will go until the comment is + * copied */ + if (*buf_ptr > 040 && *buf_ptr != '*') + ps.last_nl = 0; + CHECK_SIZE_COM; + switch (*buf_ptr) { /* this checks for various spcl cases */ + case 014: /* check for a form feed */ + if (!ps.box_com) { /* in a text comment, break the line here */ + ps.use_ff = true; + /* fix so dump_line uses a form feed */ + dump_line(); + last_bl = 0; + *e_com++ = ' '; + *e_com++ = '*'; + *e_com++ = ' '; + while (*++buf_ptr == ' ' || *buf_ptr == '\t'); + } + else { + if (++buf_ptr >= buf_end) + fill_buffer(); + *e_com++ = 014; + } + break; + + case '\n': + if (had_eof) { /* check for unexpected eof */ + printf("Unterminated comment\n"); + *e_com = '\0'; + dump_line(); + return; + } + one_liner = 0; + if (ps.box_com || ps.last_nl) { /* if this is a boxed comment, + * we dont ignore the newline */ + if (s_com == e_com) { + *e_com++ = ' '; + *e_com++ = ' '; + } + *e_com = '\0'; + if (!ps.box_com && e_com - s_com > 3) { + if (break_delim == 1 && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + dump_line(); + CHECK_SIZE_COM; + *e_com++ = ' '; + *e_com++ = ' '; + } + dump_line(); + now_col = ps.com_col; + } + else { + ps.last_nl = 1; + if (unix_comment != 1) { /* we not are in unix_style + * comment */ + if (unix_comment == 0 && s_code == e_code) { + /* + * if it is a UNIX-style comment, ignore the + * requirement that previous line be blank for + * unindention + */ + ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1; + if (ps.com_col <= 1) + ps.com_col = 2; + } + unix_comment = 2; /* permanently remember that we are in + * this type of comment */ + dump_line(); + ++line_no; + now_col = ps.com_col; + *e_com++ = ' '; + /* + * fix so that the star at the start of the line will line + * up + */ + do /* flush leading white space */ + if (++buf_ptr >= buf_end) + fill_buffer(); + while (*buf_ptr == ' ' || *buf_ptr == '\t'); + break; + } + if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t') + last_bl = e_com - 1; + /* + * if there was a space at the end of the last line, remember + * where it was + */ + else { /* otherwise, insert one */ + last_bl = e_com; + CHECK_SIZE_COM; + *e_com++ = ' '; + ++now_col; + } + } + ++line_no; /* keep track of input line number */ + if (!ps.box_com) { + int nstar = 1; + do { /* flush any blanks and/or tabs at start of + * next line */ + if (++buf_ptr >= buf_end) + fill_buffer(); + if (*buf_ptr == '*' && --nstar >= 0) { + if (++buf_ptr >= buf_end) + fill_buffer(); + if (*buf_ptr == '/') + goto end_of_comment; + } + } while (*buf_ptr == ' ' || *buf_ptr == '\t'); + } + else if (++buf_ptr >= buf_end) + fill_buffer(); + break; /* end of case for newline */ + + case '*': /* must check for possibility of being at end + * of comment */ + if (++buf_ptr >= buf_end) /* get to next char after * */ + fill_buffer(); + + if (unix_comment == 0) /* set flag to show we are not in + * unix-style comment */ + unix_comment = 1; + + if (*buf_ptr == '/') { /* it is the end!!! */ + end_of_comment: + if (++buf_ptr >= buf_end) + fill_buffer(); + + if (*(e_com - 1) != ' ' && !ps.box_com) { /* insure blank before + * end */ + *e_com++ = ' '; + ++now_col; + } + if (break_delim == 1 && !one_liner && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + if (break_delim == 2 && e_com > s_com + 3 + /* now_col > adj_max_col - 2 && !ps.box_com */ ) { + *e_com = '\0'; + dump_line(); + now_col = ps.com_col; + } + CHECK_SIZE_COM; + *e_com++ = '*'; + *e_com++ = '/'; + *e_com = '\0'; + ps.just_saw_decl = l_just_saw_decl; + return; + } + else { /* handle isolated '*' */ + *e_com++ = '*'; + ++now_col; + } + break; + default: /* we have a random char */ + if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t') + unix_comment = 1; /* we are not in unix-style comment */ + + *e_com = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + + if (*e_com == '\t') /* keep track of column */ + now_col = ((now_col - 1) & tabmask) + tabsize + 1; + else if (*e_com == '\b') /* this is a backspace */ + --now_col; + else + ++now_col; + + if (*e_com == ' ' || *e_com == '\t') + last_bl = e_com; + /* remember we saw a blank */ + + ++e_com; + if (now_col > adj_max_col && !ps.box_com && unix_comment == 1 && e_com[-1] > ' ') { + /* + * the comment is too long, it must be broken up + */ + if (break_delim == 1 && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + if (last_bl == 0) { /* we have seen no blanks */ + last_bl = e_com; /* fake it */ + *e_com++ = ' '; + } + *e_com = '\0'; /* print what we have */ + *last_bl = '\0'; + while (last_bl > s_com && last_bl[-1] < 040) + *--last_bl = 0; + e_com = last_bl; + dump_line(); + + *e_com++ = ' '; /* add blanks for continuation */ + *e_com++ = ' '; + *e_com++ = ' '; + + t_ptr = last_bl + 1; + last_bl = 0; + if (t_ptr >= e_com) { + while (*t_ptr == ' ' || *t_ptr == '\t') + t_ptr++; + while (*t_ptr != '\0') { /* move unprinted part of + * comment down in buffer */ + if (*t_ptr == ' ' || *t_ptr == '\t') + last_bl = e_com; + *e_com++ = *t_ptr++; + } + } + *e_com = '\0'; + now_col = count_spaces(ps.com_col, s_com); /* recompute current + * position */ + } + break; + } + } +} diff --git a/usr.bin/join/Makefile b/usr.bin/join/Makefile new file mode 100644 index 0000000..3fa8629 --- /dev/null +++ b/usr.bin/join/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= join + +.include diff --git a/usr.bin/join/join.1 b/usr.bin/join/join.1 new file mode 100644 index 0000000..fa383c6 --- /dev/null +++ b/usr.bin/join/join.1 @@ -0,0 +1,206 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)join.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt JOIN 1 +.Os +.Sh NAME +.Nm join +.Nd relational database operator +.Sh SYNOPSIS +.Nm join +.Oo +.Fl a Ar file_number | Fl v Ar file_number +.Oc +.Op Fl e Ar string +.Op Fl j Ar file_number field +.Op Fl o Ar list +.Bk -words +.Ek +.Op Fl t Ar char +.Op Fl \&1 Ar field +.Op Fl \&2 Ar field +.Ar file1 +.Ar file2 +.Sh DESCRIPTION +The join utility performs an ``equality join'' on the specified files +and writes the result to the standard output. +The ``join field'' is the field in each file by which the files are compared. +The first field in each line is used by default. +There is one line in the output for each pair of lines in +.Ar file1 +and +.Ar file2 +which have identical join fields. +Each output line consists of the join field, the remaining fields from +.Ar file1 +and then the remaining fields from +.Ar file2 . +.Pp +The default field separators are tab and space characters. +In this case, multiple tabs and spaces count as a single field separator, +and leading tabs and spaces are ignored. +The default output field separator is a single space character. +.Pp +Many of the options use file and field numbers. +Both file numbers and field numbers are 1 based, i.e. the first file on +the command line is file number 1 and the first field is field number 1. +The following options are available: +.Bl -tag -width Fl +.It Fl a Ar file_number +In addition to the default output, produce a line for each unpairable +line in file +.Ar file_number . +.It Fl e Ar string +Replace empty output fields with +.Ar string . +.It Fl o Ar list +The +.Fl o +option specifies the fields that will be output from each file for +each line with matching join fields. +Each element of +.Ar list +has the form +.Ql file_number.field , +where +.Ar file_number +is a file number and +.Ar field +is a field number. +The elements of list must be either comma (``,'') or whitespace separated. +(The latter requires quoting to protect it from the shell, or, a simpler +approach is to use multiple +.Fl o +options.) +.It Fl t Ar char +Use character +.Ar char +as a field delimiter for both input and output. +Every occurrence of +.Ar char +in a line is significant. +.It Fl v Ar file_number +Do not display the default output, but display a line for each unpairable +line in file +.Ar file_number . +The options +.Fl v Ar 1 +and +.Fl v Ar 2 +may be specified at the same time. +.It Fl 1 Ar field +Join on the +.Ar field Ns 'th +field of file 1. +.It Fl 2 Ar field +Join on the +.Ar field Ns 'th +field of file 2. +.El +.Pp +When the default field delimiter characters are used, the files to be joined +should be ordered in the collating sequence of +.Xr sort 1 , +using the +.Fl b +option, on the fields on which they are to be joined, otherwise +.Nm join +may not report all field matches. +When the field delimiter characters are specified by the +.Fl t +option, the collating sequence should be the same as +.Xr sort +without the +.Fl b +option. +.Pp +If one of the arguments +.Ar file1 +or +.Ar file2 +is ``-'', the standard input is used. +.Pp +The +.Nm join +utility exits 0 on success, and >0 if an error occurs. +.Sh COMPATIBILITY +For compatibility with historic versions of +.Nm join , +the following options are available: +.Bl -tag -width Fl +.It Fl a +In addition to the default output, produce a line for each unpairable line +in both file 1 and file 2. +.It Fl j1 Ar field +Join on the +.Ar field Ns 'th +field of file 1. +.It Fl j2 Ar field +Join on the +.Ar field Ns 'th +field of file 2. +.It Fl j Ar field +Join on the +.Ar field Ns 'th +field of both file 1 and file 2. +.It Fl o Ar list ... +Historical implementations of +.Nm join +permitted multiple arguments to the +.Fl o +option. +These arguments were of the form ``file_number.field_number'' as described +for the current +.Fl o +option. +This has obvious difficulties in the presence of files named ``1.2''. +.El +.Pp +These options are available only so historic shellscripts don't require +modification and should not be used. +.Sh STANDARDS +The +.Nm join +command is expected to be +.St -p1003.2 +compatible. +.Sh SEE ALSO +.Xr awk 1 , +.Xr comm 1 , +.Xr paste 1 , +.Xr sort 1 , +.Xr uniq 1 diff --git a/usr.bin/join/join.c b/usr.bin/join/join.c new file mode 100644 index 0000000..587fa84 --- /dev/null +++ b/usr.bin/join/join.c @@ -0,0 +1,582 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Steve Hayman of the Computer Science Department, Indiana University, + * Michiro Hikida and David Goodenough. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)join.c 8.3 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include + +/* + * There's a structure per input file which encapsulates the state of the + * file. We repeatedly read lines from each file until we've read in all + * the consecutive lines from the file with a common join field. Then we + * compare the set of lines with an equivalent set from the other file. + */ +typedef struct { + char *line; /* line */ + u_long linealloc; /* line allocated count */ + char **fields; /* line field(s) */ + u_long fieldcnt; /* line field(s) count */ + u_long fieldalloc; /* line field(s) allocated count */ +} LINE; + +typedef struct { + FILE *fp; /* file descriptor */ + u_long joinf; /* join field (-1, -2, -j) */ + int unpair; /* output unpairable lines (-a) */ + int number; /* 1 for file 1, 2 for file 2 */ + + LINE *set; /* set of lines with same field */ + int pushbool; /* if pushback is set */ + u_long pushback; /* line on the stack */ + u_long setcnt; /* set count */ + u_long setalloc; /* set allocated count */ +} INPUT; +INPUT input1 = { NULL, 0, 0, 1, NULL, 0, 0, 0, }, + input2 = { NULL, 0, 0, 2, NULL, 0, 0, 0, }; + +typedef struct { + u_long filenum; /* file number */ + u_long fieldno; /* field number */ +} OLIST; +OLIST *olist; /* output field list */ +u_long olistcnt; /* output field list count */ +u_long olistalloc; /* output field allocated count */ + +int joinout = 1; /* show lines with matched join fields (-v) */ +int needsep; /* need separator character */ +int spans = 1; /* span multiple delimiters (-t) */ +char *empty; /* empty field replacement string (-e) */ +char *tabchar = " \t"; /* delimiter characters (-t) */ + +int cmp __P((LINE *, u_long, LINE *, u_long)); +void fieldarg __P((char *)); +void joinlines __P((INPUT *, INPUT *)); +void obsolete __P((char **)); +void outfield __P((LINE *, u_long, int)); +void outoneline __P((INPUT *, LINE *)); +void outtwoline __P((INPUT *, LINE *, INPUT *, LINE *)); +void slurp __P((INPUT *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + INPUT *F1, *F2; + int aflag, ch, cval, vflag; + char *end; + + F1 = &input1; + F2 = &input2; + + aflag = vflag = 0; + obsolete(argv); + while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != EOF) { + switch (ch) { + case '\01': /* See comment in obsolete(). */ + aflag = 1; + F1->unpair = F2->unpair = 1; + break; + case '1': + if ((F1->joinf = strtol(optarg, &end, 10)) < 1) + errx(1, "-1 option field number less than 1"); + if (*end) + errx(1, "illegal field number -- %s", optarg); + --F1->joinf; + break; + case '2': + if ((F2->joinf = strtol(optarg, &end, 10)) < 1) + errx(1, "-2 option field number less than 1"); + if (*end) + errx(1, "illegal field number -- %s", optarg); + --F2->joinf; + break; + case 'a': + aflag = 1; + switch(strtol(optarg, &end, 10)) { + case 1: + F1->unpair = 1; + break; + case 2: + F2->unpair = 1; + break; + default: + errx(1, "-a option file number not 1 or 2"); + break; + } + if (*end) + errx(1, "illegal file number -- %s", optarg); + break; + case 'e': + empty = optarg; + break; + case 'j': + if ((F1->joinf = F2->joinf = + strtol(optarg, &end, 10)) < 1) + errx(1, "-j option field number less than 1"); + if (*end) + errx(1, "illegal field number -- %s", optarg); + --F1->joinf; + --F2->joinf; + break; + case 'o': + fieldarg(optarg); + break; + case 't': + spans = 0; + if (strlen(tabchar = optarg) != 1) + errx(1, "illegal tab character specification"); + break; + case 'v': + vflag = 1; + joinout = 0; + switch (strtol(optarg, &end, 10)) { + case 1: + F1->unpair = 1; + break; + case 2: + F2->unpair = 1; + break; + default: + errx(1, "-v option file number not 1 or 2"); + break; + } + if (*end) + errx(1, "illegal file number -- %s", optarg); + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (aflag && vflag) + errx(1, "the -a and -v options are mutually exclusive"); + + if (argc != 2) + usage(); + + /* Open the files; "-" means stdin. */ + if (!strcmp(*argv, "-")) + F1->fp = stdin; + else if ((F1->fp = fopen(*argv, "r")) == NULL) + err(1, "%s", *argv); + ++argv; + if (!strcmp(*argv, "-")) + F2->fp = stdin; + else if ((F2->fp = fopen(*argv, "r")) == NULL) + err(1, "%s", *argv); + if (F1->fp == stdin && F2->fp == stdin) + errx(1, "only one input file may be stdin"); + + slurp(F1); + slurp(F2); + while (F1->setcnt && F2->setcnt) { + cval = cmp(F1->set, F1->joinf, F2->set, F2->joinf); + if (cval == 0) { + /* Oh joy, oh rapture, oh beauty divine! */ + if (joinout) + joinlines(F1, F2); + slurp(F1); + slurp(F2); + } else if (cval < 0) { + /* File 1 takes the lead... */ + if (F1->unpair) + joinlines(F1, NULL); + slurp(F1); + } else { + /* File 2 takes the lead... */ + if (F2->unpair) + joinlines(F2, NULL); + slurp(F2); + } + } + + /* + * Now that one of the files is used up, optionally output any + * remaining lines from the other file. + */ + if (F1->unpair) + while (F1->setcnt) { + joinlines(F1, NULL); + slurp(F1); + } + if (F2->unpair) + while (F2->setcnt) { + joinlines(F2, NULL); + slurp(F2); + } + exit(0); +} + +void +slurp(F) + INPUT *F; +{ + LINE *lp, *lastlp, tmp; + size_t len; + int cnt; + char *bp, *fieldp; + + /* + * Read all of the lines from an input file that have the same + * join field. + */ + F->setcnt = 0; + for (lastlp = NULL;; ++F->setcnt, lastlp = lp) { + /* + * If we're out of space to hold line structures, allocate + * more. Initialize the structure so that we know that this + * is new space. + */ + if (F->setcnt == F->setalloc) { + cnt = F->setalloc; + F->setalloc += 50; + if ((F->set = realloc(F->set, + F->setalloc * sizeof(LINE))) == NULL) + err(1, NULL); + memset(F->set + cnt, 0, 50 * sizeof(LINE)); + } + + /* + * Get any pushed back line, else get the next line. Allocate + * space as necessary. If taking the line from the stack swap + * the two structures so that we don't lose space allocated to + * either structure. This could be avoided by doing another + * level of indirection, but it's probably okay as is. + * but it's probably okay as is. + */ + lp = &F->set[F->setcnt]; + if (F->pushbool) { + tmp = F->set[F->setcnt]; + F->set[F->setcnt] = F->set[F->pushback]; + F->set[F->pushback] = tmp; + F->pushbool = 0; + continue; + } + if ((bp = fgetln(F->fp, &len)) == NULL) + return; + if (lp->linealloc <= len + 1) { + lp->linealloc += MAX(100, len + 1); + if ((lp->line = + realloc(lp->line, lp->linealloc)) == NULL) + err(1, NULL); + } + memmove(lp->line, bp, len); + + /* 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. */ + lp->fieldcnt = 0; + while ((fieldp = strsep(&bp, tabchar)) != NULL) { + if (spans && *fieldp == '\0') + continue; + if (lp->fieldcnt == lp->fieldalloc) { + lp->fieldalloc += 50; + if ((lp->fields = realloc(lp->fields, + lp->fieldalloc * sizeof(char *))) == NULL) + err(1, NULL); + } + lp->fields[lp->fieldcnt++] = fieldp; + } + + /* See if the join field value has changed. */ + if (lastlp != NULL && cmp(lp, F->joinf, lastlp, F->joinf)) { + F->pushbool = 1; + F->pushback = F->setcnt; + break; + } + } +} + +int +cmp(lp1, fieldno1, lp2, fieldno2) + LINE *lp1, *lp2; + u_long fieldno1, fieldno2; +{ + if (lp1->fieldcnt < fieldno1) + return (lp2->fieldcnt < fieldno2 ? 0 : 1); + if (lp2->fieldcnt < fieldno2) + return (-1); + return (strcmp(lp1->fields[fieldno1], lp2->fields[fieldno2])); +} + +void +joinlines(F1, F2) + INPUT *F1, *F2; +{ + int cnt1, cnt2; + + /* + * Output the results of a join comparison. The output may be from + * either file 1 or file 2 (in which case the first argument is the + * file from which to output) or from both. + */ + if (F2 == NULL) { + for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1) + outoneline(F1, &F1->set[cnt1]); + return; + } + for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1) + for (cnt2 = 0; cnt2 < F2->setcnt; ++cnt2) + outtwoline(F1, &F1->set[cnt1], F2, &F2->set[cnt2]); +} + +void +outoneline(F, lp) + INPUT *F; + LINE *lp; +{ + int cnt; + + /* + * Output a single line from one of the files, according to the + * join rules. This happens when we are writing unmatched single + * lines. Output empty fields in the right places. + */ + if (olist) + for (cnt = 0; cnt < olistcnt; ++cnt) { + if (olist[cnt].filenum == F->number) + outfield(lp, olist[cnt].fieldno, 0); + else + outfield(lp, 0, 1); + } + else + for (cnt = 0; cnt < lp->fieldcnt; ++cnt) + outfield(lp, cnt, 0); + (void)printf("\n"); + if (ferror(stdout)) + err(1, "stdout"); + needsep = 0; +} + +void +outtwoline(F1, lp1, F2, lp2) + INPUT *F1, *F2; + LINE *lp1, *lp2; +{ + int cnt; + + /* Output a pair of lines according to the join list (if any). */ + if (olist) + for (cnt = 0; cnt < olistcnt; ++cnt) + if (olist[cnt].filenum == 1) + outfield(lp1, olist[cnt].fieldno, 0); + else /* if (olist[cnt].filenum == 2) */ + outfield(lp2, olist[cnt].fieldno, 0); + else { + /* + * Output the join field, then the remaining fields from F1 + * and F2. + */ + outfield(lp1, F1->joinf, 0); + for (cnt = 0; cnt < lp1->fieldcnt; ++cnt) + if (F1->joinf != cnt) + outfield(lp1, cnt, 0); + for (cnt = 0; cnt < lp2->fieldcnt; ++cnt) + if (F2->joinf != cnt) + outfield(lp2, cnt, 0); + } + (void)printf("\n"); + if (ferror(stdout)) + err(1, "stdout"); + needsep = 0; +} + +void +outfield(lp, fieldno, out_empty) + LINE *lp; + u_long fieldno; + int out_empty; +{ + if (needsep++) + (void)printf("%c", *tabchar); + if (!ferror(stdout)) + if (lp->fieldcnt < fieldno || out_empty) { + if (empty != NULL) + (void)printf("%s", empty); + } else { + if (*lp->fields[fieldno] == '\0') + return; + (void)printf("%s", lp->fields[fieldno]); + } + if (ferror(stdout)) + err(1, "stdout"); +} + +/* + * Convert an output list argument "2.1, 1.3, 2.4" into an array of output + * fields. + */ +void +fieldarg(option) + char *option; +{ + u_long fieldno; + char *end, *token; + + while ((token = strsep(&option, " \t")) != NULL) { + if (*token == '\0') + continue; + if (token[0] != '1' && token[0] != '2' || token[1] != '.') + errx(1, "malformed -o option field"); + fieldno = strtol(token + 2, &end, 10); + if (*end) + errx(1, "malformed -o option field"); + if (fieldno == 0) + errx(1, "field numbers are 1 based"); + if (olistcnt == olistalloc) { + olistalloc += 50; + if ((olist = realloc(olist, + olistalloc * sizeof(OLIST))) == NULL) + err(1, NULL); + } + olist[olistcnt].filenum = token[0] - '0'; + olist[olistcnt].fieldno = fieldno - 1; + ++olistcnt; + } +} + +void +obsolete(argv) + char **argv; +{ + int len; + char **p, *ap, *t; + + while ((ap = *++argv) != NULL) { + /* Return if "--". */ + if (ap[0] == '-' && ap[1] == '-') + return; + switch (ap[1]) { + case 'a': + /* + * The original join allowed "-a", which meant the + * same as -a1 plus -a2. POSIX 1003.2, Draft 11.2 + * only specifies this as "-a 1" and "a -2", so we + * have to use another option flag, one that is + * unlikely to ever be used or accidentally entered + * on the command line. (Well, we could reallocate + * the argv array, but that hardly seems worthwhile.) + */ + if (ap[2] == '\0') + ap[1] = '\01'; + break; + case 'j': + /* + * The original join allowed "-j[12] arg" and "-j arg". + * Convert the former to "-[12] arg". Don't convert + * the latter since getopt(3) can handle it. + */ + switch(ap[2]) { + case '1': + if (ap[3] != '\0') + goto jbad; + ap[1] = '1'; + ap[2] = '\0'; + break; + case '2': + if (ap[3] != '\0') + goto jbad; + ap[1] = '2'; + ap[2] = '\0'; + break; + case '\0': + break; + default: +jbad: errx(1, "illegal option -- %s", ap); + usage(); + } + break; + case 'o': + /* + * The original join allowed "-o arg arg". + * Convert to "-o arg -o arg". + */ + if (ap[2] != '\0') + break; + for (p = argv + 2; *p; ++p) { + if (p[0][0] != '1' && + p[0][0] != '2' || p[0][1] != '.') + break; + len = strlen(*p); + if (len - 2 != strspn(*p + 2, "0123456789")) + break; + if ((t = malloc(len + 3)) == NULL) + err(1, NULL); + t[0] = '-'; + t[1] = 'o'; + memmove(t + 2, *p, len + 1); + *p = t; + } + argv = p - 1; + break; + } + } +} + +void +usage() +{ + (void)fprintf(stderr, "%s%s\n", + "usage: join [-a fileno | -v fileno ] [-e string] [-1 field] ", + "[-2 field]\n [-o list] [-t char] file1 file2"); + exit(1); +} diff --git a/usr.bin/jot/Makefile b/usr.bin/jot/Makefile new file mode 100644 index 0000000..83db4c0 --- /dev/null +++ b/usr.bin/jot/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= jot + +.include diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1 new file mode 100644 index 0000000..c7dba58 --- /dev/null +++ b/usr.bin/jot/jot.1 @@ -0,0 +1,195 @@ +.\" 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. +.\" +.\" @(#)jot.1 8.1 (Berkeley) 6/6/93 +.\" +.TH JOT 1 "June 6, 1993" +.UC 4 +.SH NAME +jot \- print sequential or random data +.SH SYNOPSIS +.B jot [ +options +.B ] [ +\fRreps \fB[\fP begin \fB[\fP end \fB[\fP s \fB] ] ] ]\fP +.SH DESCRIPTION +.I Jot +is used to print out increasing, decreasing, random, +or redundant data, usually numbers, one per line. +The +.I options +are understood as follows. +.IP \fB\-r\fP +Generate random data instead of sequential data, the default. +.IP \fB\-b\fP\ word +Just print +.I word +repetitively. +.IP \fB\-w\fP\ word +Print +.IR word +with the generated data appended to it. +Octal, hexadecimal, exponential, ASCII, zero padded, +and right-adjusted representations +are possible by using the appropriate +.IR printf (3) +conversion specification inside +.IR word , +in which case the data are inserted rather than appended. +.IP \fB\-c\fP +This is an abbreviation for \fB\-w %c\fP. +.IP \fB\-s\fP\ string +Print data separated by +.IR string . +Normally, newlines separate data. +.IP \fB\-n\fP +Do not print the final newline normally appended to the output. +.IP \fB\-p\fP\ precision +Print only as many digits or characters of the data +as indicated by the integer +.IR precision . +In the absence of +.BR \-p , +the precision is the greater of the precisions of +.I begin +and +.IR end . +The +.B \-p +option is overridden by whatever appears in a +.IR printf (3) +conversion following +.BR \-w . +.PP +The last four arguments indicate, respectively, +the number of data, the lower bound, the upper bound, +and the step size or, for random data, the seed. +While at least one of them must appear, +any of the other three may be omitted, and +will be considered as such if given as +.BR \- . +Any three of these arguments determines the fourth. +If four are specified and the given and computed values of +.I reps +conflict, the lower value is used. +If fewer than three are specified, defaults are assigned +left to right, except for +.IR s , +which assumes its default unless both +.I begin +and +.I end +are given. +.PP +Defaults for the four arguments are, respectively, +100, 1, 100, and 1, except that when random data are requested, +.I s +defaults to a seed depending upon the time of day. +.I Reps +is expected to be an unsigned integer, +and if given as zero is taken to be infinite. +.I Begin +and +.I end +may be given as real numbers or as characters +representing the corresponding value in ASCII. +The last argument must be a real number. +.PP +Random numbers are obtained through +.IR random (3). +The name +.I jot +derives in part from +.IR iota , +a function in APL. +.SH EXAMPLES +.de IC +.IP +.ss 36 +.ft B +.. +.de NC +.br +.ss 12 +.PP +.. +.PP +The command +.IC +jot 21 \-1 1.00 +.NC +prints 21 evenly spaced numbers increasing from \-1 to 1. +The ASCII character set is generated with +.IC +jot \-c 128 0 +.NC +and the strings xaa through xaz with +.IC +jot \-w xa%c 26 a +.NC +while 20 random 8-letter strings are produced with +.IC +jot \-r \-c 160 a z | rs \-g 0 8 +.NC +Infinitely many +.IR yes 's +may be obtained through +.IC +jot \-b yes 0 +.NC +and thirty +.IR ed (1) +substitution commands applying to lines 2, 7, 12, etc. is +the result of +.IC +jot \-w %ds/old/new/ 30 2 \- 5 +.NC +The stuttering sequence 9, 9, 8, 8, 7, etc. can be +produced by suitable choice of precision and step size, +as in +.IC +jot 0 9 \- \-.5 +.NC +and a file containing exactly 1024 bytes is created with +.IC +jot \-b x 512 > block +.NC +Finally, to set tabs four spaces apart starting +from column 10 and ending in column 132, use +.IC +expand \-\`jot \-s, \- 10 132 4\` +.NC +and to print all lines 80 characters or longer, +.IC +grep \`jot \-s "" \-b . 80\` +.NC +.SH SEE ALSO +ed(1), expand(1), rs(1), yes(1), printf(3), random(3), expand(1) diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c new file mode 100644 index 0000000..442d083 --- /dev/null +++ b/usr.bin/jot/jot.c @@ -0,0 +1,393 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * jot - print sequential or random data + * + * Author: John Kunze, Office of Comp. Affairs, UCB + */ + +#include +#include +#include +#include +#include +#include + +#define REPS_DEF 100 +#define BEGIN_DEF 1 +#define ENDER_DEF 100 +#define STEP_DEF 1 + +#define isdefault(s) (strcmp((s), "-") == 0) + +double begin; +double ender; +double s; +long reps; +int randomize; +int infinity; +int boring; +int prec; +int dox; +int chardata; +int nofinalnl; +char *sepstring = "\n"; +char format[BUFSIZ]; + +void error __P((char *, char *)); +void getargs __P((int, char *[])); +void getformat __P((void)); +int getprec __P((char *)); +void putdata __P((double, long)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + double xd, yd; + long id; + register double *x = &xd; + register double *y = &yd; + register long *i = &id; + + getargs(argc, argv); + if (randomize) { + *x = (ender - begin) * (ender > begin ? 1 : -1); + srandom((int) s); + for (*i = 1; *i <= reps || infinity; (*i)++) { + *y = (double) random() / INT_MAX; + putdata(*y * *x + begin, reps - *i); + } + } + else + for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) + putdata(*x, reps - *i); + if (!nofinalnl) + putchar('\n'); + exit(0); +} + +void +getargs(ac, av) + int ac; + char *av[]; +{ + register unsigned int mask = 0; + register int n = 0; + + while (--ac && **++av == '-' && !isdefault(*av)) + switch ((*av)[1]) { + case 'r': + randomize = 1; + break; + case 'c': + chardata = 1; + break; + case 'n': + nofinalnl = 1; + break; + case 'b': + boring = 1; + case 'w': + if ((*av)[2]) + strcpy(format, *av + 2); + else if (!--ac) + error("Need context word after -w or -b", ""); + else + strcpy(format, *++av); + break; + case 's': + if ((*av)[2]) + strcpy(sepstring, *av + 2); + else if (!--ac) + error("Need string after -s", ""); + else + strcpy(sepstring, *++av); + break; + case 'p': + if ((*av)[2]) + prec = atoi(*av + 2); + else if (!--ac) + error("Need number after -p", ""); + else + prec = atoi(*++av); + if (prec <= 0) + error("Bad precision value", ""); + break; + default: + error("Unknown option %s", *av); + } + + switch (ac) { /* examine args right to left, falling thru cases */ + case 4: + if (!isdefault(av[3])) { + if (!sscanf(av[3], "%lf", &s)) + error("Bad s value: %s", av[3]); + mask |= 01; + } + case 3: + if (!isdefault(av[2])) { + if (!sscanf(av[2], "%lf", &ender)) + ender = av[2][strlen(av[2])-1]; + mask |= 02; + if (!prec) + n = getprec(av[2]); + } + case 2: + if (!isdefault(av[1])) { + if (!sscanf(av[1], "%lf", &begin)) + begin = av[1][strlen(av[1])-1]; + mask |= 04; + if (!prec) + prec = getprec(av[1]); + if (n > prec) /* maximum precision */ + prec = n; + } + case 1: + if (!isdefault(av[0])) { + if (!sscanf(av[0], "%ld", &reps)) + error("Bad reps value: %s", av[0]); + mask |= 010; + } + break; + case 0: + error("jot - print sequential or random data", ""); + default: + error("Too many arguments. What do you mean by %s?", av[4]); + } + getformat(); + while (mask) /* 4 bit mask has 1's where last 4 args were given */ + switch (mask) { /* fill in the 0's by default or computation */ + case 001: + reps = REPS_DEF; + mask = 011; + break; + case 002: + reps = REPS_DEF; + mask = 012; + break; + case 003: + reps = REPS_DEF; + mask = 013; + break; + case 004: + reps = REPS_DEF; + mask = 014; + break; + case 005: + reps = REPS_DEF; + mask = 015; + break; + case 006: + reps = REPS_DEF; + mask = 016; + break; + case 007: + if (randomize) { + reps = REPS_DEF; + mask = 0; + break; + } + if (s == 0.0) { + reps = 0; + mask = 0; + break; + } + reps = (ender - begin + s) / s; + if (reps <= 0) + error("Impossible stepsize", ""); + mask = 0; + break; + case 010: + begin = BEGIN_DEF; + mask = 014; + break; + case 011: + begin = BEGIN_DEF; + mask = 015; + break; + case 012: + s = (randomize ? time(0) : STEP_DEF); + mask = 013; + break; + case 013: + if (randomize) + begin = BEGIN_DEF; + else if (reps == 0) + error("Must specify begin if reps == 0", ""); + begin = ender - reps * s + s; + mask = 0; + break; + case 014: + s = (randomize ? time(0) : STEP_DEF); + mask = 015; + break; + case 015: + if (randomize) + ender = ENDER_DEF; + else + ender = begin + reps * s - s; + mask = 0; + break; + case 016: + if (randomize) + s = time(0); + else if (reps == 0) + error("Infinite sequences cannot be bounded", + ""); + else if (reps == 1) + s = 0.0; + else + s = (ender - begin) / (reps - 1); + mask = 0; + break; + case 017: /* if reps given and implied, */ + if (!randomize && s != 0.0) { + long t = (ender - begin + s) / s; + if (t <= 0) + error("Impossible stepsize", ""); + if (t < reps) /* take lesser */ + reps = t; + } + mask = 0; + break; + default: + error("Bad mask", ""); + } + if (reps == 0) + infinity = 1; +} + +void +putdata(x, notlast) + double x; + long notlast; +{ + long d = x; + register long *dp = &d; + + if (boring) /* repeated word */ + printf(format); + else if (dox) /* scalar */ + printf(format, *dp); + else /* real */ + printf(format, x); + if (notlast != 0) + fputs(sepstring, stdout); +} + +void +error(msg, s) + char *msg, *s; +{ + fprintf(stderr, "jot: "); + fprintf(stderr, msg, s); + fprintf(stderr, + "\nusage: jot [ options ] [ reps [ begin [ end [ s ] ] ] ]\n"); + if (strncmp("jot - ", msg, 6) == 0) + fprintf(stderr, "Options:\n\t%s\t%s\t%s\t%s\t%s\t%s\t%s", + "-r random data\n", + "-c character data\n", + "-n no final newline\n", + "-b word repeated word\n", + "-w word context word\n", + "-s string data separator\n", + "-p precision number of characters\n"); + exit(1); +} + +int +getprec(s) + char *s; +{ + register char *p; + register char *q; + + for (p = s; *p; p++) + if (*p == '.') + break; + if (!*p) + return (0); + for (q = ++p; *p; p++) + if (!isdigit(*p)) + break; + return (p - q); +} + +void +getformat() +{ + register char *p; + + if (boring) /* no need to bother */ + return; + for (p = format; *p; p++) /* look for '%' */ + if (*p == '%' && *(p+1) != '%') /* leave %% alone */ + break; + if (!*p && !chardata) + sprintf(p, "%%.%df", prec); + else if (!*p && chardata) { + strcpy(p, "%c"); + dox = 1; + } + else if (!*(p+1)) + strcat(format, "%"); /* cannot end in single '%' */ + else { + while (!isalpha(*p)) + p++; + switch (*p) { + case 'f': case 'e': case 'g': case '%': + break; + case 's': + error("Cannot convert numeric data to strings", ""); + break; + /* case 'd': case 'o': case 'x': case 'D': case 'O': case 'X': + case 'c': case 'u': */ + default: + dox = 1; + break; + } + } +} diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile new file mode 100644 index 0000000..0f8add8 --- /dev/null +++ b/usr.bin/kdump/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= kdump +CFLAGS+=-I${.CURDIR}/../ktrace +SRCS= kdump.c ioctl.c subr.c +.PATH: ${.CURDIR}/../ktrace +CLEANFILES+=ioctl.c + +ioctl.c: mkioctls + /bin/sh ${.CURDIR}/mkioctls > ioctl.c + +.include diff --git a/usr.bin/kdump/kdump.1 b/usr.bin/kdump/kdump.1 new file mode 100644 index 0000000..5db704f --- /dev/null +++ b/usr.bin/kdump/kdump.1 @@ -0,0 +1,100 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kdump.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt KDUMP 1 +.Os BSD 4.4 +.Sh NAME +.Nm kdump +.Nd display kernel trace data +.Sh SYNOPSIS +.Nm kdump +.Op Fl dnlRT +.Op Fl f Ar file +.Op Fl m Ar maxdata +.Op Fl t Op cnis +.Sh DESCRIPTION +.Nm Kdump +displays the kernel trace files produced with +.Xr ktrace 1 +in human readable format. +By default, the file +.Pa ktrace.out +in the current directory is displayed. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl d +Display all numbers in decimal. +.It Fl f Ar file +Display the specified file instead of +.Pa ktrace.out . +.It Fl l +Loop reading the trace file, once the end-of-file is reached, waiting for +more data. +.It Fl m Ar maxdata +Display at most +.Ar maxdata +bytes when decoding +.Tn I/O . +.It Fl n +Suppress ad hoc translations. +Normally +.Nm kdump +tries to decode many system calls into a more human readable format. +For example, +.Xr ioctl 2 +values are replaced with the macro name and +.Va errno +values are replaced with the +.Xr strerror 3 +string. +Suppressing this feature yields a more consistent output format and is +easily amenable to further processing. +.It Fl R +Display relative timestamps (time since previous entry). +.It Fl T +Display absolute timestamps for each entry (seconds since epoch). +.It Fl t Ar cnis +See the +.Fl t +option of +.Xr ktrace 1 . +.El +.Sh SEE ALSO +.Xr ktrace 1 +.Sh HISTORY +The +.Nm kdump +command appears in +.Bx 4.4 . diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c new file mode 100644 index 0000000..988bbbc --- /dev/null +++ b/usr.bin/kdump/kdump.c @@ -0,0 +1,437 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#define KERNEL +#include +#undef KERNEL +#include +#include +#include +#include +#include "ktrace.h" + +int timestamp, decimal, fancy = 1, tail, maxdata; +char *tracefile = DEF_TRACEFILE; +struct ktr_header ktr_header; + +#define eqs(s1, s2) (strcmp((s1), (s2)) == 0) + +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int ch, ktrlen, size; + register void *m; + int trpoints = ALL_POINTS; + + while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != EOF) + switch((char)ch) { + case 'f': + tracefile = optarg; + break; + case 'd': + decimal = 1; + break; + case 'l': + tail = 1; + break; + case 'm': + maxdata = atoi(optarg); + break; + case 'n': + fancy = 0; + break; + case 'R': + timestamp = 2; /* relative timestamp */ + break; + case 'T': + timestamp = 1; + break; + case 't': + trpoints = getpoints(optarg); + if (trpoints < 0) { + (void)fprintf(stderr, + "kdump: unknown trace point in %s\n", + optarg); + exit(1); + } + break; + default: + usage(); + } + argv += optind; + argc -= optind; + + if (argc > 1) + usage(); + + m = (void *)malloc(size = 1025); + if (m == NULL) { + (void)fprintf(stderr, "kdump: %s.\n", strerror(ENOMEM)); + exit(1); + } + if (!freopen(tracefile, "r", stdin)) { + (void)fprintf(stderr, + "kdump: %s: %s.\n", tracefile, strerror(errno)); + exit(1); + } + while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { + if (trpoints & (1< size) { + m = (void *)realloc(m, ktrlen+1); + if (m == NULL) { + (void)fprintf(stderr, + "kdump: %s.\n", strerror(ENOMEM)); + exit(1); + } + size = ktrlen; + } + if (ktrlen && fread_tail(m, ktrlen, 1) == 0) { + (void)fprintf(stderr, "kdump: data too short.\n"); + exit(1); + } + if ((trpoints & (1<ktr_type) { + case KTR_SYSCALL: + type = "CALL"; + break; + case KTR_SYSRET: + type = "RET "; + break; + case KTR_NAMEI: + type = "NAMI"; + break; + case KTR_GENIO: + type = "GIO "; + break; + case KTR_PSIG: + type = "PSIG"; + break; + case KTR_CSW: + type = "CSW"; + break; + default: + (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); + type = unknown; + } + + (void)printf("%6d %-8s ", kth->ktr_pid, kth->ktr_comm); + if (timestamp) { + if (timestamp == 2) { + temp = kth->ktr_time; + timevalsub(&kth->ktr_time, &prevtime); + prevtime = temp; + } + (void)printf("%ld.%06ld ", + kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); + } + (void)printf("%s ", type); +} + +#include +#define KTRACE +#include "/sys/kern/syscalls.c" +#undef KTRACE +int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); + +static char *ptrace_ops[] = { + "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", + "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", + "PT_KILL", "PT_STEP", +}; + +ktrsyscall(ktr) + register struct ktr_syscall *ktr; +{ + register narg = ktr->ktr_narg; + register int *ip; + char *ioctlname(); + + if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) + (void)printf("[%d]", ktr->ktr_code); + else + (void)printf("%s", syscallnames[ktr->ktr_code]); + ip = (int *)((char *)ktr + sizeof(struct ktr_syscall)); + if (narg) { + char c = '('; + if (fancy) { + if (ktr->ktr_code == SYS_ioctl) { + char *cp; + if (decimal) + (void)printf("(%d", *ip); + else + (void)printf("(%#x", *ip); + ip++; + narg--; + if ((cp = ioctlname(*ip)) != NULL) + (void)printf(",%s", cp); + else { + if (decimal) + (void)printf(",%d", *ip); + else + (void)printf(",%#x ", *ip); + } + c = ','; + ip++; + narg--; + } else if (ktr->ktr_code == SYS_ptrace) { + if (*ip <= PT_STEP && *ip >= 0) + (void)printf("(%s", ptrace_ops[*ip]); + else + (void)printf("(%d", *ip); + c = ','; + ip++; + narg--; + } + } + while (narg) { + if (decimal) + (void)printf("%c%d", c, *ip); + else + (void)printf("%c%#x", c, *ip); + c = ','; + ip++; + narg--; + } + (void)putchar(')'); + } + (void)putchar('\n'); +} + +ktrsysret(ktr) + struct ktr_sysret *ktr; +{ + register int ret = ktr->ktr_retval; + register int error = ktr->ktr_error; + register int code = ktr->ktr_code; + + if (code >= nsyscalls || code < 0) + (void)printf("[%d] ", code); + else + (void)printf("%s ", syscallnames[code]); + + if (error == 0) { + if (fancy) { + (void)printf("%d", ret); + if (ret < 0 || ret > 9) + (void)printf("/%#x", ret); + } else { + if (decimal) + (void)printf("%d", ret); + else + (void)printf("%#x", ret); + } + } else if (error == ERESTART) + (void)printf("RESTART"); + else if (error == EJUSTRETURN) + (void)printf("JUSTRETURN"); + else { + (void)printf("-1 errno %d", ktr->ktr_error); + if (fancy) + (void)printf(" %s", strerror(ktr->ktr_error)); + } + (void)putchar('\n'); +} + +ktrnamei(cp, len) + char *cp; +{ + (void)printf("\"%.*s\"\n", len, cp); +} + +ktrgenio(ktr, len) + struct ktr_genio *ktr; +{ + register int datalen = len - sizeof (struct ktr_genio); + register char *dp = (char *)ktr + sizeof (struct ktr_genio); + register char *cp; + register int col = 0; + register width; + char visbuf[5]; + static screenwidth = 0; + + if (screenwidth == 0) { + struct winsize ws; + + if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && + ws.ws_col > 8) + screenwidth = ws.ws_col; + else + screenwidth = 80; + } + printf("fd %d %s %d bytes\n", ktr->ktr_fd, + ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); + if (maxdata && datalen > maxdata) + datalen = maxdata; + (void)printf(" \""); + col = 8; + for (;datalen > 0; datalen--, dp++) { + (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); + cp = visbuf; + /* + * Keep track of printables and + * space chars (like fold(1)). + */ + if (col == 0) { + (void)putchar('\t'); + col = 8; + } + switch(*cp) { + case '\n': + col = 0; + (void)putchar('\n'); + continue; + case '\t': + width = 8 - (col&07); + break; + default: + width = strlen(cp); + } + if (col + width > (screenwidth-2)) { + (void)printf("\\\n\t"); + col = 8; + } + col += width; + do { + (void)putchar(*cp++); + } while (*cp); + } + if (col == 0) + (void)printf(" "); + (void)printf("\"\n"); +} + +char *signames[] = { + "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ + "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ + "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ + "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ + "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ + "USR2", NULL, /* 31 - 32 */ +}; + +ktrpsig(psig) + struct ktr_psig *psig; +{ + (void)printf("SIG%s ", signames[psig->signo]); + if (psig->action == SIG_DFL) + (void)printf("SIG_DFL\n"); + else + (void)printf("caught handler=0x%x mask=0x%x code=0x%x\n", + (u_int)psig->action, psig->mask, psig->code); +} + +ktrcsw(cs) + struct ktr_csw *cs; +{ + (void)printf("%s %s\n", cs->out ? "stop" : "resume", + cs->user ? "user" : "kernel"); +} + +usage() +{ + (void)fprintf(stderr, + "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n"); + exit(1); +} diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls new file mode 100644 index 0000000..acba53b --- /dev/null +++ b/usr.bin/kdump/mkioctls @@ -0,0 +1,33 @@ +awk ' +BEGIN { + print "#include " + print "#include " + print "#include " + print "#include " + print "#include " + print "#include " + print "#define COMPAT_43" + print "#include " + print "" + print "char *" + print "ioctlname(val)" + print "{" + print "" +} + +/^#[ ]*define[ ]*(TIO|FIO|SIO|OSIO)[A-Z]*[ ]*_IO/ { + + # find where the name starts + for (i = 1; i <= NF; i++) + if ($i ~ /define/) + break; + ++i; + # + printf("\tif (val == %s)\n\t\treturn(\"%s\");\n", $i, $i); + +} +END { + print "\n\treturn(NULL);" + print "}" +} +' /usr/include/sys/ioctl.h /usr/include/sys/ioctl_compat.h diff --git a/usr.bin/ktrace/Makefile b/usr.bin/ktrace/Makefile new file mode 100644 index 0000000..53a253f --- /dev/null +++ b/usr.bin/ktrace/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ktrace +SRCS= ktrace.c subr.c + +.include diff --git a/usr.bin/ktrace/ktrace.1 b/usr.bin/ktrace/ktrace.1 new file mode 100644 index 0000000..d080b4e --- /dev/null +++ b/usr.bin/ktrace/ktrace.1 @@ -0,0 +1,163 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ktrace.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt KTRACE 1 +.Os BSD 4.4 +.Sh NAME +.Nm ktrace +.Nd enable kernel process tracing +.Sh SYNOPSIS +.Nm ktrace +.Op Fl aCcdi +.Op Fl f Ar trfile +.Op Fl g Ar pgrp +.Op Fl p Ar pid +.Op Fl t Ar trstr +.Nm ktrace +.Op Fl adi +.Op Fl f Ar trfile +.Op Fl t Ar trstr +command +.Sh DESCRIPTION +.Nm Ktrace +enables kernel trace logging for the specified processes. +Kernel trace data is logged to the file +.Pa ktrace.out . +The kernel operations that are traced include system calls, namei +translations, signal processing, and +.Tn I/O . +.Pp +Once tracing is enabled on a process, trace data will be logged until +either the process exits or the trace point is cleared. +A traced process can generate enormous amounts of log data quickly; +It is strongly suggested that users memorize how to disable tracing before +attempting to trace a process. +The following command is sufficient to disable tracing on all user owned +processes, and, if executed by root, all processes: +.Pp +.Dl \&$ trace -C +.Pp +The trace file is not human readable; use +.Xr kdump 1 +to decode it. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a +Append to the trace file instead of truncating it. +.It Fl C +Disable tracing on all user owned processes, and, if executed by root, all +processes in the system. +.It Fl c +Clear the trace points associated with the specified file or processes. +.It Fl d +Descendants; perform the operation for all current children of the +designated processes. +.It Fl f Ar file +Log trace records to +.Ar file +instead of +.Pa ktrace.out . +.It Fl g Ar pgid +Enable (disable) tracing on all processes in the process group (only one +.Fl g +flag is permitted). +.It Fl i +Inherit; pass the trace flags to all future children of the designated +processes. +.It Fl p Ar pid +Enable (disable) tracing on the indicated process id (only one +.Fl p +flag is permitted). +.It Fl t Ar trstr +The string argument represents the kernel trace points, one per letter. +The following table equates the letters with the tracepoints: +.Pp +.Bl -tag -width flag -compact +.It Cm c +trace system calls +.It Cm n +trace namei translations +.It Cm i +trace +.Tn I/O +.It Cm s +trace signal processing +.El +.It Ar command +Execute +.Ar command +with the specified trace flags. +.El +.Pp +The +.Fl p , +.Fl g , +and +.Ar command +options are mutually exclusive. +.Sh EXAMPLES +# trace all kernel operations of process id 34 +.Dl $ ktrace -p 34 +.Pp +# trace all kernel operations of processes in process group 15 and +# pass the trace flags to all current and future children +.Dl $ ktrace -idg 15 +.Pp +# disable all tracing of process 65 +.Dl $ ktrace -cp 65 +.Pp +# disable tracing signals on process 70 and all current children +.Dl $ ktrace -t s -cdp 70 +.Pp +# enable tracing of +.Tn I/O +on process 67 +.Dl $ ktrace -ti -p 67 +.Pp +# run the command "w", tracing only system calls +.Dl $ ktrace -tc w +.Pp +# disable all tracing to the file "tracedata" +.Dl $ ktrace -c -f tracedata +.Pp +# disable tracing of all processes owned by the user +.Dl $ ktrace -C +.Sh SEE ALSO +.Xr kdump 1 +.Sh HISTORY +The +.Nm ktrace +command appears in +.Bx 4.4 . diff --git a/usr.bin/ktrace/ktrace.c b/usr.bin/ktrace/ktrace.c new file mode 100644 index 0000000..26606d7 --- /dev/null +++ b/usr.bin/ktrace/ktrace.c @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ktrace.h" + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + extern char *optarg; + enum { NOTSET, CLEAR, CLEARALL } clear; + int append, ch, fd, inherit, ops, pid, pidset, trpoints; + char *tracefile; + + clear = NOTSET; + append = ops = pidset = inherit = 0; + trpoints = DEF_POINTS; + tracefile = DEF_TRACEFILE; + while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != EOF) + switch((char)ch) { + case 'a': + append = 1; + break; + case 'C': + clear = CLEARALL; + pidset = 1; + break; + case 'c': + clear = CLEAR; + break; + case 'd': + ops |= KTRFLAG_DESCEND; + break; + case 'f': + tracefile = optarg; + break; + case 'g': + pid = -rpid(optarg); + pidset = 1; + break; + case 'i': + inherit = 1; + break; + case 'p': + pid = rpid(optarg); + pidset = 1; + break; + case 't': + trpoints = getpoints(optarg); + if (trpoints < 0) { + (void)fprintf(stderr, + "ktrace: unknown facility in %s\n", optarg); + usage(); + } + break; + default: + usage(); + } + argv += optind; + argc -= optind; + + if (pidset && *argv || !pidset && !*argv) + usage(); + + if (inherit) + trpoints |= KTRFAC_INHERIT; + + if (clear != NOTSET) { + if (clear == CLEARALL) { + ops = KTROP_CLEAR | KTRFLAG_DESCEND; + trpoints = ALL_POINTS; + pid = 1; + } else + ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE; + + if (ktrace(tracefile, ops, trpoints, pid) < 0) + error(tracefile); + exit(0); + } + + if ((fd = open(tracefile, O_CREAT | O_WRONLY | (append ? 0 : O_TRUNC), + DEFFILEMODE)) < 0) + error(tracefile); + (void)close(fd); + + if (*argv) { + if (ktrace(tracefile, ops, trpoints, getpid()) < 0) + error(); + execvp(argv[0], &argv[0]); + error(argv[0]); + exit(1); + } + else if (ktrace(tracefile, ops, trpoints, pid) < 0) + error(tracefile); + exit(0); +} + +rpid(p) + char *p; +{ + static int first; + + if (first++) { + (void)fprintf(stderr, + "ktrace: only one -g or -p flag is permitted.\n"); + usage(); + } + if (!*p) { + (void)fprintf(stderr, "ktrace: illegal process id.\n"); + usage(); + } + return(atoi(p)); +} + +error(name) + char *name; +{ + (void)fprintf(stderr, "ktrace: %s: %s.\n", name, strerror(errno)); + exit(1); +} + +usage() +{ + (void)fprintf(stderr, +"usage:\tktrace [-aCcid] [-f trfile] [-g pgid] [-p pid] [-t [acgn]\n\tktrace [-aCcid] [-f trfile] [-t [acgn] command\n"); + exit(1); +} diff --git a/usr.bin/ktrace/ktrace.h b/usr.bin/ktrace/ktrace.h new file mode 100644 index 0000000..595b8bc --- /dev/null +++ b/usr.bin/ktrace/ktrace.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)ktrace.h 8.1 (Berkeley) 6/6/93 + */ + +#define DEF_POINTS (KTRFAC_SYSCALL | KTRFAC_SYSRET | KTRFAC_NAMEI | \ + KTRFAC_GENIO | KTRFAC_PSIG) + +#define ALL_POINTS (DEF_POINTS | KTRFAC_CSW) + +#define DEF_TRACEFILE "ktrace.out" diff --git a/usr.bin/ktrace/subr.c b/usr.bin/ktrace/subr.c new file mode 100644 index 0000000..6076c24 --- /dev/null +++ b/usr.bin/ktrace/subr.c @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "ktrace.h" + +getpoints(s) + char *s; +{ + int facs = 0; + + while (*s) { + switch(*s) { + case 'c': + facs |= KTRFAC_SYSCALL | KTRFAC_SYSRET; + break; + case 'n': + facs |= KTRFAC_NAMEI; + break; + case 'i': + facs |= KTRFAC_GENIO; + break; + case 's': + facs |= KTRFAC_PSIG; + break; + case 'w': + facs |= KTRFAC_CSW; + break; + case '+': + facs |= DEF_POINTS; + break; + default: + return (-1); + } + s++; + } + return (facs); +} + +timevaladd(t1, t2) + struct timeval *t1, *t2; +{ + t1->tv_sec += t2->tv_sec; + t1->tv_usec += t2->tv_usec; + timevalfix(t1); +} + +timevalsub(t1, t2) + struct timeval *t1, *t2; +{ + t1->tv_sec -= t2->tv_sec; + t1->tv_usec -= t2->tv_usec; + timevalfix(t1); +} + +timevalfix(t1) + struct timeval *t1; +{ + if (t1->tv_usec < 0) { + t1->tv_sec--; + t1->tv_usec += 1000000; + } + if (t1->tv_usec >= 1000000) { + t1->tv_sec++; + t1->tv_usec -= 1000000; + } +} diff --git a/usr.bin/lam/Makefile b/usr.bin/lam/Makefile new file mode 100644 index 0000000..a24fc92 --- /dev/null +++ b/usr.bin/lam/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= lam + +.include diff --git a/usr.bin/lam/lam.1 b/usr.bin/lam/lam.1 new file mode 100644 index 0000000..660e5dc --- /dev/null +++ b/usr.bin/lam/lam.1 @@ -0,0 +1,127 @@ +.\" 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. +.\" +.\" @(#)lam.1 8.1 (Berkeley) 6/6/93 +.\" +.TH LAM 1 "June 6, 1993" +.UC 4 +.SH NAME +lam \- laminate files +.SH SYNOPSIS +.B lam [ \-[fp] +min.max +.B ] [ \-s +sepstring +.B ] [ \-t +c +.B ] +file ... +.SH DESCRIPTION +.I Lam +copies the named files side by side onto the standard output. +The +.IR n -th +input lines from the input +.IR file s +are considered fragments of the single long +.IR n -th +output line into which they are assembled. +The name `\fB\-\fP' means the standard input, and may be repeated. +.PP +Normally, each option affects only the +.I file +after it. +If the option letter is capitalized it affects all subsequent files +until it appears again uncapitalized. +The options are described below. +.IP \fB\-f\fP\ min.max +Print line fragments according to the format string +.IR min.max , +where +.I min +is the minimum field width and +.I max +the maximum field width. +If +.I min +begins with a zero, zeros will be added to make up the field width, +and if it begins with a `\-', the fragment will be left-adjusted +within the field. +.IP \fB\-p\fP\ min.max +Like \fB\-f\fP, +but pad this file's field when end-of-file is reached +and other files are still active. +.IP \fB\-s\fP\ sepstring +Print +.I sepstring +before printing line fragments from the next file. +This option may appear after the last file. +.IP \fB\-t\fP\ c +The input line terminator is +.I c +instead of a newline. +The newline normally appended to each output line is omitted. +.PP +To print files simultaneously for easy viewing use +.IR pr (1). +.SH EXAMPLES +.de IC +.IP +.ss 36 +.ft B +.. +.de NC +.br +.ss 12 +.PP +.. +.PP +The command +.IC +lam file1 file2 file3 file4 +.NC +joins 4 files together along each line. +To merge the lines from four different files use +.IC +lam file1 \-S "\\ +.br +" file2 file3 file4 +.NC +Every 2 lines of a file may be joined on one line with +.IC +lam \- \- < file +.NC +and a form letter with substitutions keyed by `@' can be done with +.IC +lam \-t @ letter changes +.NC +.SH SEE ALSO +join(1), pr(1), printf(3) diff --git a/usr.bin/lam/lam.c b/usr.bin/lam/lam.c new file mode 100644 index 0000000..07d6abb --- /dev/null +++ b/usr.bin/lam/lam.c @@ -0,0 +1,233 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * lam - laminate files + * Author: John Kunze, UCB + */ + +#include +#include +#include + +#define MAXOFILES 20 +#define BIGBUFSIZ 5 * BUFSIZ + +struct openfile { /* open file structure */ + FILE *fp; /* file pointer */ + short eof; /* eof flag */ + short pad; /* pad flag for missing columns */ + char eol; /* end of line character */ + char *sepstring; /* string to print before each line */ + char *format; /* printf(3) style string spec. */ +} input[MAXOFILES]; + +int morefiles; /* set by getargs(), changed by gatherline() */ +int nofinalnl; /* normally append \n to each output line */ +char line[BIGBUFSIZ]; +char *linep; + +void error __P((char *, char *)); +char *gatherline __P((struct openfile *)); +void getargs __P((char *[])); +char *pad __P((struct openfile *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register struct openfile *ip; + + getargs(argv); + if (!morefiles) + error("lam - laminate files", ""); + for (;;) { + linep = line; + for (ip = input; ip->fp != NULL; ip++) + linep = gatherline(ip); + if (!morefiles) + exit(0); + fputs(line, stdout); + fputs(ip->sepstring, stdout); + if (!nofinalnl) + putchar('\n'); + } +} + +void +getargs(av) + char *av[]; +{ + register struct openfile *ip = input; + register char *p; + register char *c; + static char fmtbuf[BUFSIZ]; + char *fmtp = fmtbuf; + int P, S, F, T; + + P = S = F = T = 0; /* capitalized options */ + while ((p = *++av) != NULL) { + if (*p != '-' || !p[1]) { + morefiles++; + if (*p == '-') + ip->fp = stdin; + else if ((ip->fp = fopen(p, "r")) == NULL) { + perror(p); + exit(1); + } + ip->pad = P; + if (!ip->sepstring) + ip->sepstring = (S ? (ip-1)->sepstring : ""); + if (!ip->format) + ip->format = ((P || F) ? (ip-1)->format : "%s"); + if (!ip->eol) + ip->eol = (T ? (ip-1)->eol : '\n'); + ip++; + continue; + } + switch (*(c = ++p) | 040) { + case 's': + if (*++p || (p = *++av)) + ip->sepstring = p; + else + error("Need string after -%s", c); + S = (*c == 'S' ? 1 : 0); + break; + case 't': + if (*++p || (p = *++av)) + ip->eol = *p; + else + error("Need character after -%s", c); + T = (*c == 'T' ? 1 : 0); + nofinalnl = 1; + break; + case 'p': + ip->pad = 1; + P = (*c == 'P' ? 1 : 0); + case 'f': + F = (*c == 'F' ? 1 : 0); + if (*++p || (p = *++av)) { + fmtp += strlen(fmtp) + 1; + if (fmtp > fmtbuf + BUFSIZ) + error("No more format space", ""); + sprintf(fmtp, "%%%ss", p); + ip->format = fmtp; + } + else + error("Need string after -%s", c); + break; + default: + error("What do you mean by -%s?", c); + break; + } + } + ip->fp = NULL; + if (!ip->sepstring) + ip->sepstring = ""; +} + +char * +pad(ip) + struct openfile *ip; +{ + register char *p = ip->sepstring; + register char *lp = linep; + + while (*p) + *lp++ = *p++; + if (ip->pad) { + sprintf(lp, ip->format, ""); + lp += strlen(lp); + } + return (lp); +} + +char * +gatherline(ip) + struct openfile *ip; +{ + char s[BUFSIZ]; + register int c; + register char *p; + register char *lp = linep; + char *end = s + BUFSIZ; + + if (ip->eof) + return (pad(ip)); + for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++) + if ((*p = c) == ip->eol) + break; + *p = '\0'; + if (c == EOF) { + ip->eof = 1; + if (ip->fp == stdin) + fclose(stdin); + morefiles--; + return (pad(ip)); + } + p = ip->sepstring; + while (*p) + *lp++ = *p++; + sprintf(lp, ip->format, s); + lp += strlen(lp); + return (lp); +} + +void +error(msg, s) + char *msg, *s; +{ + fprintf(stderr, "lam: "); + fprintf(stderr, msg, s); + fprintf(stderr, +"\nUsage: lam [ -[fp] min.max ] [ -s sepstring ] [ -t c ] file ...\n"); + if (strncmp("lam - ", msg, 6) == 0) + fprintf(stderr, "Options:\n\t%s\t%s\t%s\t%s\t%s", + "-f min.max field widths for file fragments\n", + "-p min.max like -f, but pad missing fragments\n", + "-s sepstring fragment separator\n", +"-t c input line terminator is c, no \\n after output lines\n", + "Capitalized options affect more than one file.\n"); + exit(1); +} diff --git a/usr.bin/last/Makefile b/usr.bin/last/Makefile new file mode 100644 index 0000000..edbb66b --- /dev/null +++ b/usr.bin/last/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= last + +.include diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1 new file mode 100644 index 0000000..27a214d --- /dev/null +++ b/usr.bin/last/last.1 @@ -0,0 +1,123 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)last.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LAST 1 +.Os BSD 4 +.Sh NAME +.Nm last +.Nd indicate last logins of users and ttys +.Sh SYNOPSIS +.Nm last +.Op Fl Ns Ar n +.Op Fl f Ar file +.Op Fl h Ar host +.Op Fl t Ar tty +.Op user ... +.Sh DESCRIPTION +.Nm Last +will list the sessions of specified +.Ar users , +.Ar ttys , +and +.Ar hosts , +in reverse time order. Each line of output contains +the user name, the tty from which the session was conducted, any +hostname, the start and stop times for the session, and the duration +of the session. If the session is still continuing or was cut short by +a crash or shutdown, +.Nm last +will so indicate. +.Pp +.Bl -tag -width indent-two +.It Fl f Ar file +.Nm Last +reads the file +.Ar file +instead of the default, +.Pa /var/log/wtmp . +.It Fl Ar n +Limits the report to +.Ar n +lines. +.It Fl t Ar tty +Specify the +.Ar tty . +Tty names may be given fully or abbreviated, for example, +.Dq Li "last -t 03" +is +equivalent to +.Dq Li "last -t tty03" . +.It Fl h Ar host +.Ar Host +names may be names or internet numbers. +.El +.Pp +If +multiple arguments are given, the information which applies to any of the +arguments is printed, e.g., +.Dq Li "last root -t console" +would list all of +.Dq Li root Ns 's +sessions as well as all sessions on the console terminal. If no +users, hostnames or terminals are specified, +.Nm last +prints a record of +all logins and logouts. +.Pp +The pseudo-user +.Ar reboot +logs in at reboots of the system, thus +.Dq Li last reboot +will give an indication of mean time between reboot. +.Pp +If +.Nm last +is interrupted, it indicates to what date the search has +progressed. If interrupted with a quit signal +.Nm last +indicates how +far the search has progressed and then continues. +.Sh FILES +.Bl -tag -width /var/log/wtmp -compact +.It Pa /var/log/wtmp +login data base +.El +.Sh SEE ALSO +.Xr lastcomm 1 , +.Xr utmp 5 , +.Xr ac 8 +.Sh HISTORY +.Nm Last +appeared in +.Bx 3.0 . diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c new file mode 100644 index 0000000..662a663 --- /dev/null +++ b/usr.bin/last/last.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NO 0 /* false/no */ +#define YES 1 /* true/yes */ + +static struct utmp buf[1024]; /* utmp read buffer */ + +typedef struct arg { + char *name; /* argument */ +#define HOST_TYPE -2 +#define TTY_TYPE -3 +#define USER_TYPE -4 + int type; /* type of arg */ + struct arg *next; /* linked list pointer */ +} ARG; +ARG *arglist; /* head of linked list */ + +typedef struct ttytab { + long logout; /* log out time */ + char tty[UT_LINESIZE + 1]; /* terminal name */ + struct ttytab *next; /* linked list pointer */ +} TTY; +TTY *ttylist; /* head of linked list */ + +static long currentout, /* current logout value */ + maxrec; /* records to display */ +static char *file = _PATH_WTMP; /* wtmp file */ + +void addarg __P((int, char *)); +TTY *addtty __P((char *)); +void hostconv __P((char *)); +void onintr __P((int)); +char *ttyconv __P((char *)); +int want __P((struct utmp *, int)); +void wtmp __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int ch; + char *p; + + maxrec = -1; + while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: last was originally designed to take + * a number after a dash. + */ + if (maxrec == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + maxrec = atol(++p); + else + maxrec = atol(argv[optind] + 1); + if (!maxrec) + exit(0); + } + break; + case 'f': + file = optarg; + break; + case 'h': + hostconv(optarg); + addarg(HOST_TYPE, optarg); + break; + case 't': + addarg(TTY_TYPE, ttyconv(optarg)); + break; + case '?': + default: + (void)fprintf(stderr, + "usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n"); + exit(1); + } + + if (argc) { + setlinebuf(stdout); + for (argv += optind; *argv; ++argv) { +#define COMPATIBILITY +#ifdef COMPATIBILITY + /* code to allow "last p5" to work */ + addarg(TTY_TYPE, ttyconv(*argv)); +#endif + addarg(USER_TYPE, *argv); + } + } + wtmp(); + exit(0); +} + +/* + * wtmp -- + * read through the wtmp file + */ +void +wtmp() +{ + struct utmp *bp; /* current structure */ + TTY *T; /* tty list entry */ + struct stat stb; /* stat of file for size */ + long bl, delta; /* time difference */ + int bytes, wfd; + char *ct, *crmsg; + + if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) + err(1, "%s", file); + bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf); + + (void)time(&buf[0].ut_time); + (void)signal(SIGINT, onintr); + (void)signal(SIGQUIT, onintr); + + while (--bl >= 0) { + if (lseek(wfd, (off_t)(bl * sizeof(buf)), L_SET) == -1 || + (bytes = read(wfd, buf, sizeof(buf))) == -1) + err(1, "%s", file); + for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) { + /* + * if the terminal line is '~', the machine stopped. + * see utmp(5) for more info. + */ + if (bp->ut_line[0] == '~' && !bp->ut_line[1]) { + /* everybody just logged out */ + for (T = ttylist; T; T = T->next) + T->logout = -bp->ut_time; + currentout = -bp->ut_time; + crmsg = strncmp(bp->ut_name, "shutdown", + UT_NAMESIZE) ? "crash" : "shutdown"; + if (want(bp, NO)) { + ct = ctime(&bp->ut_time); + printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n", + UT_NAMESIZE, UT_NAMESIZE, + bp->ut_name, UT_LINESIZE, + UT_LINESIZE, bp->ut_line, + UT_HOSTSIZE, UT_HOSTSIZE, + bp->ut_host, ct, ct + 11); + if (maxrec != -1 && !--maxrec) + return; + } + continue; + } + /* + * if the line is '{' or '|', date got set; see + * utmp(5) for more info. + */ + if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|') + && !bp->ut_line[1]) { + if (want(bp, NO)) { + ct = ctime(&bp->ut_time); + printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n", + UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, + UT_LINESIZE, UT_LINESIZE, bp->ut_line, + UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, + ct, ct + 11); + if (maxrec && !--maxrec) + return; + } + continue; + } + /* find associated tty */ + for (T = ttylist;; T = T->next) { + if (!T) { + /* add new one */ + T = addtty(bp->ut_line); + break; + } + if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE)) + break; + } + if (bp->ut_name[0] && want(bp, YES)) { + ct = ctime(&bp->ut_time); + printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ", + UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, + UT_LINESIZE, UT_LINESIZE, bp->ut_line, + UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, + ct, ct + 11); + if (!T->logout) + puts(" still logged in"); + else { + if (T->logout < 0) { + T->logout = -T->logout; + printf("- %s", crmsg); + } + else + printf("- %5.5s", + ctime(&T->logout)+11); + delta = T->logout - bp->ut_time; + if (delta < SECSPERDAY) + printf(" (%5.5s)\n", + asctime(gmtime(&delta))+11); + else + printf(" (%ld+%5.5s)\n", + delta / SECSPERDAY, + asctime(gmtime(&delta))+11); + } + if (maxrec != -1 && !--maxrec) + return; + } + T->logout = bp->ut_time; + } + } + ct = ctime(&buf[0].ut_time); + printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); +} + +/* + * want -- + * see if want this entry + */ +int +want(bp, check) + struct utmp *bp; + int check; +{ + ARG *step; + + if (check) + /* + * when uucp and ftp log in over a network, the entry in + * the utmp file is the name plus their process id. See + * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. + */ + 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'; + if (!arglist) + return (YES); + + for (step = arglist; step; step = step->next) + switch(step->type) { + case HOST_TYPE: + if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE)) + return (YES); + break; + case TTY_TYPE: + if (!strncmp(step->name, bp->ut_line, UT_LINESIZE)) + return (YES); + break; + case USER_TYPE: + if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE)) + return (YES); + break; + } + return (NO); +} + +/* + * addarg -- + * add an entry to a linked list of arguments + */ +void +addarg(type, arg) + int type; + char *arg; +{ + ARG *cur; + + if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) + err(1, "malloc failure"); + cur->next = arglist; + cur->type = type; + cur->name = arg; + arglist = cur; +} + +/* + * addtty -- + * add an entry to a linked list of ttys + */ +TTY * +addtty(ttyname) + char *ttyname; +{ + TTY *cur; + + if (!(cur = (TTY *)malloc((u_int)sizeof(TTY)))) + err(1, "malloc failure"); + cur->next = ttylist; + cur->logout = currentout; + memmove(cur->tty, ttyname, UT_LINESIZE); + return (ttylist = cur); +} + +/* + * hostconv -- + * convert the hostname to search pattern; if the supplied host name + * has a domain attached that is the same as the current domain, rip + * off the domain suffix since that's what login(1) does. + */ +void +hostconv(arg) + char *arg; +{ + static int first = 1; + static char *hostdot, name[MAXHOSTNAMELEN]; + char *argdot; + + if (!(argdot = strchr(arg, '.'))) + return; + if (first) { + first = 0; + if (gethostname(name, sizeof(name))) + err(1, "gethostname"); + hostdot = strchr(name, '.'); + } + if (hostdot && !strcasecmp(hostdot, argdot)) + *argdot = '\0'; +} + +/* + * ttyconv -- + * convert tty to correct name. + */ +char * +ttyconv(arg) + char *arg; +{ + char *mval; + + /* + * kludge -- we assume that all tty's end with + * a two character suffix. + */ + if (strlen(arg) == 2) { + /* either 6 for "ttyxx" or 8 for "console" */ + if (!(mval = malloc((u_int)8))) + err(1, "malloc failure"); + if (!strcmp(arg, "co")) + (void)strcpy(mval, "console"); + else { + (void)strcpy(mval, "tty"); + (void)strcpy(mval + 3, arg); + } + return (mval); + } + if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) + return (arg + 5); + return (arg); +} + +/* + * onintr -- + * on interrupt, we inform the user how far we've gotten + */ +void +onintr(signo) + int signo; +{ + char *ct; + + ct = ctime(&buf[0].ut_time); + printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11); + if (signo == SIGINT) + exit(1); + (void)fflush(stdout); /* fix required for rsh */ +} diff --git a/usr.bin/lastcomm/Makefile b/usr.bin/lastcomm/Makefile new file mode 100644 index 0000000..9061573 --- /dev/null +++ b/usr.bin/lastcomm/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= lastcomm + +.include diff --git a/usr.bin/lastcomm/lastcomm.1 b/usr.bin/lastcomm/lastcomm.1 new file mode 100644 index 0000000..1542b0d --- /dev/null +++ b/usr.bin/lastcomm/lastcomm.1 @@ -0,0 +1,124 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lastcomm.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LASTCOMM 1 +.Os BSD 3 +.Sh NAME +.Nm lastcomm +.Nd show last commands executed in reverse order +.Sh SYNOPSIS +.Nm lastcomm +.Op Fl f Ar file +.Op Ar command ... +.Op Ar user ... +.Op Ar terminal ... +.Sh DESCRIPTION +.Nm Lastcomm +gives information on previously executed commands. +With no arguments, +.Nm lastcomm +prints information about all the commands recorded +during the current accounting file's lifetime. +.Pp +Option: +.Pp +.Bl -tag -width Fl +.It Fl f Ar file +Read from +.Ar file +rather than the default +accounting file. +.El +.Pp +If called with arguments, only accounting entries with a +matching +.Ar command +name, +.Ar user +name, +or +.Ar terminal +name +are printed. +So, for example: +.Pp +.Dl lastcomm a.out root ttyd0 +.Pp +would produce a listing of all the +executions of commands named +.Pa a.out +by user +.Ar root +on the terminal +.Ar ttyd0 . +.Pp +For each process entry, the following are printed. +.Pp +.Bl -bullet -offset indent -compact +.It +The name of the user who ran the process. +.It +Flags, as accumulated by the accounting facilities in the system. +.It +The command name under which the process was called. +.It +The amount of cpu time used by the process (in seconds). +.It +The time the process exited. +.El +.Pp +The flags are encoded as follows: ``S'' indicates the command was +executed by the super-user, ``F'' indicates the command ran after +a fork, but without a following +.Xr exec , +``C'' indicates the command was run in PDP-11 compatibility mode +(VAX only), +``D'' indicates the command terminated with the generation of a +.Pa core +file, and ``X'' indicates the command was terminated with a signal. +.Sh FILES +.Bl -tag -width /var/account/acct -compact +.It Pa /var/account/acct +Default accounting file. +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr sigvec 2 , +.Xr acct 5 , +.Xr core 5 +.Sh HISTORY +The +.Nm lastcomm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c new file mode 100644 index 0000000..7c3c363 --- /dev/null +++ b/usr.bin/lastcomm/lastcomm.c @@ -0,0 +1,222 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +time_t expand __P((u_int)); +char *flagbits __P((int)); +char *getdev __P((dev_t)); +int requested __P((char *[], struct acct *)); +void usage __P((void)); +char *user_from_uid(); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char *p; + struct acct ab; + struct stat sb; + FILE *fp; + off_t size; + time_t t; + int ch; + char *acctfile; + + acctfile = _PATH_ACCT; + while ((ch = getopt(argc, argv, "f:")) != EOF) + switch((char)ch) { + case 'f': + acctfile = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* Open the file. */ + if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb)) + err(1, "%s", acctfile); + + /* + * Round off to integral number of accounting records, probably + * not necessary, but it doesn't hurt. + */ + size = sb.st_size - sb.st_size % sizeof(struct acct); + + /* Check if any records to display. */ + if (size < sizeof(struct acct)) + exit(0); + + /* + * Seek to before the last entry in the file; use lseek(2) in case + * the file is bigger than a "long". + */ + size -= sizeof(struct acct); + if (lseek(fileno(fp), size, SEEK_SET) == -1) + err(1, "%s", acctfile); + + for (;;) { + if (fread(&ab, sizeof(struct acct), 1, fp) != 1) + err(1, "%s", acctfile); + + if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1) + err(1, "%s", acctfile); + + if (size == 0) + break; + size -= sizeof(struct acct); + + if (ab.ac_comm[0] == '\0') { + ab.ac_comm[0] = '?'; + ab.ac_comm[1] = '\0'; + } else + for (p = &ab.ac_comm[0]; + p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p) + if (!isprint(*p)) + *p = '?'; + if (*argv && !requested(argv, &ab)) + continue; + + t = expand(ab.ac_utime) + expand(ab.ac_stime); + (void)printf("%-*s %-7s %-*s %-*s %6.2f secs %.16s\n", + fldsiz(acct, ac_comm), ab.ac_comm, flagbits(ab.ac_flag), + UT_NAMESIZE, user_from_uid(ab.ac_uid, 0), + UT_LINESIZE, getdev(ab.ac_tty), + t / (double)AHZ, ctime(&ab.ac_btime)); + } + exit(0); +} + +time_t +expand(t) + u_int t; +{ + register time_t nt; + + nt = t & 017777; + t >>= 13; + while (t) { + t--; + nt <<= 3; + } + return (nt); +} + +char * +flagbits(f) + register int f; +{ + static char flags[20] = "-"; + char *p; + +#define BIT(flag, ch) if (f & flag) *p++ = ch + + p = flags + 1; + BIT(ASU, 'S'); + BIT(AFORK, 'F'); + BIT(ACOMPAT, 'C'); + BIT(ACORE, 'D'); + BIT(AXSIG, 'X'); + *p = '\0'; + return (flags); +} + +int +requested(argv, acp) + register char *argv[]; + register struct acct *acp; +{ + register char *p; + + do { + p = user_from_uid(acp->ac_uid, 0); + if (!strcmp(p, *argv)) + return (1); + if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv)) + return (1); + if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) + return (1); + } while (*++argv); + return (0); +} + +char * +getdev(dev) + dev_t dev; +{ + static dev_t lastdev = (dev_t)-1; + static char *lastname; + + if (dev == NODEV) /* Special case. */ + return ("__"); + if (dev == lastdev) /* One-element cache. */ + return (lastname); + lastdev = dev; + lastname = devname(dev, S_IFCHR); + return (lastname); +} + +void +usage() +{ + (void)fprintf(stderr, + "lastcomm [ -f file ] [command ...] [user ...] [tty ...]\n"); + exit(1); +} diff --git a/usr.bin/lastcomm/pathnames.h b/usr.bin/lastcomm/pathnames.h new file mode 100644 index 0000000..0737970 --- /dev/null +++ b/usr.bin/lastcomm/pathnames.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_ACCT "/var/account/acct" diff --git a/usr.bin/ld/Makefile b/usr.bin/ld/Makefile new file mode 100644 index 0000000..834a5c9 --- /dev/null +++ b/usr.bin/ld/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ld +SRCS= ld.c cplus-dem.c +NOMAN= noman + +.include diff --git a/usr.bin/ld/cplus-dem.c b/usr.bin/ld/cplus-dem.c new file mode 100644 index 0000000..b2e3050 --- /dev/null +++ b/usr.bin/ld/cplus-dem.c @@ -0,0 +1,970 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + */ + +#ifndef lint +static char sccsid[] = "@(#)cplus-dem.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* Demangler for GNU C++ + Copyright (C) 1989 Free Software Foundation, Inc. + written by James Clark (jjc@jclark.uucp) + + This program is free software; you can 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. */ + +/* This is for g++ 1.36.1 (November 6 version). It will probably + require changes for any other version. + + Modified for g++ 1.36.2 (November 18 version). */ + +/* This file exports one function + + char *cplus_demangle (const char *name) + + If `name' is a mangled function name produced by g++, 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. + + For example, + + cplus_demangle ("_foo__1Ai") + + returns + + "A::foo(int)" + + 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. */ + +/* #define nounderscore 1 /* define this is names don't start with _ */ + +#include +#include + +#ifdef USG +#include +#include +#else +#include +#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n)) +#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n)) +#define strchr index +#define strrchr rindex +#endif + +#ifdef __STDC__ +extern char *cplus_demangle (const char *type); +#else +extern char *cplus_demangle (); +#endif + +#ifdef __STDC__ +extern char *xmalloc (int); +extern char *xrealloc (char *, int); +#else +extern char *xmalloc (); +extern char *xrealloc (); +#endif + +static char **typevec = 0; +static int ntypes = 0; +static int typevec_size = 0; + +static struct { + const char *in; + const char *out; +} optable[] = { + "new", " new", + "delete", " delete", + "ne", "!=", + "eq", "==", + "ge", ">=", + "gt", ">", + "le", "<=", + "lt", "<", + "plus", "+", + "minus", "-", + "mult", "*", + "convert", "+", /* unary + */ + "negate", "-", /* unary - */ + "trunc_mod", "%", + "trunc_div", "/", + "truth_andif", "&&", + "truth_orif", "||", + "truth_not", "!", + "postincrement", "++", + "postdecrement", "--", + "bit_ior", "|", + "bit_xor", "^", + "bit_and", "&", + "bit_not", "~", + "call", "()", + "cond", "?:", + "alshift", "<<", + "arshift", ">>", + "component", "->", + "indirect", "*", + "method_call", "->()", + "addr", "&", /* unary & */ + "array", "[]", + "nop", "", /* for operator= */ +}; + +/* Beware: these aren't '\0' terminated. */ + +typedef struct { + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#ifdef __STDC__ +static void string_need (string *s, int n); +static void string_delete (string *s); +static void string_init (string *s); +static void string_clear (string *s); +static int string_empty (string *s); +static void string_append (string *p, const char *s); +static void string_appends (string *p, string *s); +static void string_appendn (string *p, const char *s, int n); +static void string_prepend (string *p, const char *s); +#if 0 +static void string_prepends (string *p, string *s); +#endif +static void string_prependn (string *p, const char *s, int n); +static int get_count (const char **type, int *count); +static int do_args (const char **type, string *decl); +static int do_type (const char **type, string *result); +static int do_arg (const char **type, string *result); +static int do_args (const char **type, string *decl); +static void munge_function_name (string *name); +static void remember_type (const char *type, int len); +#else +static void string_need (); +static void string_delete (); +static void string_init (); +static void string_clear (); +static int string_empty (); +static void string_append (); +static void string_appends (); +static void string_appendn (); +static void string_prepend (); +static void string_prepends (); +static void string_prependn (); +static int get_count (); +static int do_args (); +static int do_type (); +static int do_arg (); +static int do_args (); +static void munge_function_name (); +static void remember_type (); +#endif + +char * +cplus_demangle (type) + const char *type; +{ + string decl; + int n; + int success = 0; + int constructor = 0; + int const_flag = 0; + int i; + const char *p; +#ifndef LONGERNAMES + const char *premangle; +#endif + + if (type == NULL || *type == '\0') + return NULL; +#ifndef nounderscore + if (*type++ != '_') + return NULL; +#endif + p = type; + while (*p != '\0' && !(*p == '_' && p[1] == '_')) + p++; + if (*p == '\0') + { + /* destructor */ + if (type[0] == '_' && type[1] == '$' && type[2] == '_') + { + int n = (strlen (type) - 3)*2 + 3 + 2 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 3); + strcat (tem, "::~"); + strcat (tem, type + 3); + strcat (tem, "()"); + return tem; + } + /* static data member */ + if (*type != '_' && (p = strchr (type, '$')) != NULL) + { + int n = strlen (type) + 2; + char *tem = (char *) xmalloc (n); + memcpy (tem, type, p - type); + strcpy (tem + (p - type), "::"); + strcpy (tem + (p - type) + 2, p + 1); + return tem; + } + /* virtual table */ + if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$') + { + int n = strlen (type + 4) + 14 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 4); + strcat (tem, " virtual table"); + return tem; + } + return NULL; + } + + string_init (&decl); + + if (p == type) + { + if (!isdigit (p[2])) + { + string_delete (&decl); + return NULL; + } + constructor = 1; + } + else + { + string_appendn (&decl, type, p - type); + munge_function_name (&decl); + } + p += 2; + +#ifndef LONGERNAMES + premangle = p; +#endif + switch (*p) + { + case 'C': + /* a const member function */ + if (!isdigit (p[1])) + { + string_delete (&decl); + return NULL; + } + p += 1; + const_flag = 1; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (strlen (p) < n) + { + string_delete (&decl); + return NULL; + } + if (constructor) + { + string_appendn (&decl, p, n); + string_append (&decl, "::"); + string_appendn (&decl, p, n); + } + else + { + string_prepend (&decl, "::"); + string_prependn (&decl, p, n); + } + p += n; +#ifndef LONGERNAMES + remember_type (premangle, p - premangle); +#endif + success = do_args (&p, &decl); + if (const_flag) + string_append (&decl, " const"); + break; + case 'F': + p += 1; + success = do_args (&p, &decl); + break; + } + + for (i = 0; i < ntypes; i++) + if (typevec[i] != NULL) + free (typevec[i]); + ntypes = 0; + if (typevec != NULL) + { + free ((char *)typevec); + typevec = NULL; + typevec_size = 0; + } + + if (success) + { + string_appendn (&decl, "", 1); + return decl.b; + } + else + { + string_delete (&decl); + return NULL; + } +} + +static int +get_count (type, count) + const char **type; + int *count; +{ + if (!isdigit (**type)) + return 0; + *count = **type - '0'; + *type += 1; + /* see flush_repeats in cplus-method.c */ + if (isdigit (**type)) + { + const char *p = *type; + int n = *count; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + 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 (type, result) + const char **type; + string *result; +{ + int n; + int done; + int non_empty = 0; + int success; + string decl; + const char *remembered_type; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**type) + { + case 'P': + *type += 1; + string_prepend (&decl, "*"); + break; + + case 'R': + *type += 1; + string_prepend (&decl, "&"); + break; + + case 'T': + *type += 1; + if (!get_count (type, &n) || n >= ntypes) + success = 0; + else + { + remembered_type = typevec[n]; + type = &remembered_type; + } + break; + + case 'F': + *type += 1; + if (!string_empty (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + if (!do_args (type, &decl) || **type != '_') + success = 0; + else + *type += 1; + break; + + case 'M': + case 'O': + { + int constp = 0; + int volatilep = 0; + + member = **type == 'M'; + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *type, n); + string_prepend (&decl, "("); + *type += n; + if (member) + { + if (**type == 'C') + { + *type += 1; + constp = 1; + } + if (**type == 'V') + { + *type += 1; + volatilep = 1; + } + if (*(*type)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !do_args (type, &decl)) || **type != '_') + { + success = 0; + break; + } + *type += 1; + if (constp) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "const"); + } + if (volatilep) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "volatilep"); + } + break; + } + + case 'C': + if ((*type)[1] == 'P') + { + *type += 1; + if (!string_empty (&decl)) + string_prepend (&decl, " "); + string_prepend (&decl, "const"); + break; + } + + /* fall through */ + default: + done = 1; + break; + } + } + + done = 0; + non_empty = 0; + while (success && !done) + { + switch (**type) + { + case 'C': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "const"); + break; + case 'U': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "unsigned"); + break; + case 'V': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "volatile"); + break; + default: + done = 1; + break; + } + } + + if (success) + switch (**type) + { + case '\0': + case '_': + break; + case 'v': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "void"); + break; + case 'x': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long long"); + break; + case 'l': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long"); + break; + case 'i': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "int"); + break; + case 's': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "short"); + break; + case 'c': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "char"); + break; + case 'r': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long double"); + break; + case 'd': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "double"); + break; + case 'f': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "float"); + break; + case 'G': + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + if (non_empty) + string_append (result, " "); + string_appendn (result, *type, n); + *type += n; + break; + default: + success = 0; + break; + } + + if (success) + { + if (!string_empty (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + string_delete (&decl); + return 1; + } + else + { + string_delete (&decl); + string_delete (result); + return 0; + } +} + +/* `result' will be initialised in do_type; it will be freed on failure */ + +static int +do_arg (type, result) + const char **type; + string *result; +{ + const char *start = *type; + + if (!do_type (type, result)) + return 0; + remember_type (start, *type - start); + return 1; +} + +static void +remember_type (start, len) + const char *start; + int len; +{ + char *tem; + + if (ntypes >= typevec_size) + { + if (typevec_size == 0) + { + typevec_size = 3; + typevec = (char **) xmalloc (sizeof (char*)*typevec_size); + } + else + { + typevec_size *= 2; + typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size); + } + } + tem = (char *) xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + typevec[ntypes++] = tem; +} + +/* `decl' must be already initialised, usually non-empty; + it won't be freed on failure */ + +static int +do_args (type, decl) + const char **type; + string *decl; +{ + string arg; + int need_comma = 0; + + string_append (decl, "("); + + while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v') + { + if (**type == 'N') + { + int r; + int t; + *type += 1; + if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes) + return 0; + while (--r >= 0) + { + const char *tem = typevec[t]; + if (need_comma) + string_append (decl, ", "); + if (!do_arg (&tem, &arg)) + return 0; + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma) + string_append (decl, ", "); + if (!do_arg (type, &arg)) + return 0; + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**type == 'v') + *type += 1; + else if (**type == 'e') + { + *type += 1; + if (need_comma) + string_append (decl, ","); + string_append (decl, "..."); + } + + string_append (decl, ")"); + return 1; +} + +static void +munge_function_name (name) + string *name; +{ + if (!string_empty (name) && name->p - name->b >= 3 + && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$') + { + int i; + /* see if it's an assignment expression */ + if (name->p - name->b >= 10 /* op$assign_ */ + && memcmp (name->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 10, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + string_append (name, "="); + return; + } + } + } + else + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 3, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + return; + } + } + } + return; + } + else if (!string_empty (name) && name->p - name->b >= 5 + && memcmp (name->b, "type$", 5) == 0) + { + /* type conversion operator */ + string type; + const char *tem = name->b + 5; + if (do_type (&tem, &type)) + { + string_clear (name); + string_append (name, "operator "); + string_appends (name, &type); + string_delete (&type); + return; + } + } +} + +/* a mini string-handling package */ + +static void +string_need (s, n) + string *s; + int n; +{ + if (s->b == NULL) + { + if (n < 32) + n = 32; + s->p = s->b = (char *) xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + int tem = s->p - s->b; + n += tem; + n *= 2; + s->b = (char *) 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; +} + +static int +string_empty (s) + string *s; +{ + return s->b == s->p; +} + +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) + return; + 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) + return; + 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') + return; + string_prependn (p, s, strlen (s)); +} + +#if 0 +static void +string_prepends (p, s) + string *p, *s; +{ + if (s->b == s->p) + return; + string_prependn (p, s->b, s->p - s->b); +} +#endif + +static void +string_prependn (p, s, n) + string *p; + const char *s; + int n; +{ + char *q; + + if (n == 0) + return; + 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; +} diff --git a/usr.bin/ld/ld.c b/usr.bin/ld/ld.c new file mode 100644 index 0000000..f0b35f2 --- /dev/null +++ b/usr.bin/ld/ld.c @@ -0,0 +1,4718 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)ld.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* Linker `ld' for GNU + Copyright (C) 1988 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You 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 Richard Stallman with some help from Eric Albert. + Set, indirect, and warning symbol features added by Randy Smith. */ + +/* Define how to initialize system-dependent header fields. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* symseg.h defines the obsolete GNU debugging format; we should nuke it. */ +#define CORE_ADDR unsigned long /* For symseg.h */ +#include "symseg.h" + +#define N_SET_MAGIC(exec, val) ((exec).a_magic = val) + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#endif + +#define min(a,b) ((a) < (b) ? (a) : (b)) + +/* Macro to control the number of undefined references printed */ +#define MAX_UREFS_PRINTED 10 + +/* Size of a page; obtained from the operating system. */ + +int page_size; + +/* Name this program was invoked by. */ + +char *progname; + +/* System dependencies */ + +/* Define this to specify the default executable format. */ + +#ifndef DEFAULT_MAGIC +#define DEFAULT_MAGIC ZMAGIC +#endif + +#if defined(hp300) || defined(luna68k) +#define INITIALIZE_HEADER outheader.a_mid = MID_HP300 +#endif + +#ifdef sparc +#ifndef sun +#define sun 1 +#endif +#define INITIALIZE_HEADER \ + (outheader.a_mid = MID_SUN_SPARC, outheader.a_toolversion = 1) +#endif + +/* + * Ok. Following are the relocation information macros. If your + * system should not be able to use the default set (below), you must + * define the following: + + * relocation_info: This must be typedef'd (or #define'd) to the type + * of structure that is stored in the relocation info section of your + * a.out files. Often this is defined in the a.out.h for your system. + * + * RELOC_ADDRESS (rval): Offset into the current section of the + * to be relocated. *Must be an lvalue*. + * + * RELOC_EXTERN_P (rval): Is this relocation entry based on an + * external symbol (1), or was it fully resolved upon entering the + * loader (0) in which case some combination of the value in memory + * (if RELOC_MEMORY_ADD_P) and the extra (if RELOC_ADD_EXTRA) contains + * what the value of the relocation actually was. *Must be an lvalue*. + * + * RELOC_TYPE (rval): If this entry was fully resolved upon + * entering the loader, what type should it be relocated as? + * + * RELOC_SYMBOL (rval): If this entry was not fully resolved upon + * entering the loader, what is the index of it's symbol in the symbol + * table? *Must be a lvalue*. + * + * RELOC_MEMORY_ADD_P (rval): This should return true if the final + * relocation value output here should be added to memory, or if the + * section of memory described should simply be set to the relocation + * value. + * + * RELOC_ADD_EXTRA (rval): (Optional) This macro, if defined, gives + * an extra value to be added to the relocation value based on the + * individual relocation entry. *Must be an lvalue if defined*. + * + * RELOC_PCREL_P (rval): True if the relocation value described is + * pc relative. + * + * RELOC_VALUE_RIGHTSHIFT (rval): Number of bits right to shift the + * final relocation value before putting it where it belongs. + * + * RELOC_TARGET_SIZE (rval): log to the base 2 of the number of + * bytes of size this relocation entry describes; 1 byte == 0; 2 bytes + * == 1; 4 bytes == 2, and etc. This is somewhat redundant (we could + * do everything in terms of the bit operators below), but having this + * macro could end up producing better code on machines without fancy + * bit twiddling. Also, it's easier to understand/code big/little + * endian distinctions with this macro. + * + * RELOC_TARGET_BITPOS (rval): The starting bit position within the + * object described in RELOC_TARGET_SIZE in which the relocation value + * will go. + * + * RELOC_TARGET_BITSIZE (rval): How many bits are to be replaced + * with the bits of the relocation value. It may be assumed by the + * code that the relocation value will fit into this many bits. This + * may be larger than RELOC_TARGET_SIZE if such be useful. + * + * + * Things I haven't implemented + * ---------------------------- + * + * Values for RELOC_TARGET_SIZE other than 0, 1, or 2. + * + * Pc relative relocation for External references. + * + * + */ + +/* The following #if has been modifed for cross compilation */ +/* It originally read: #if defined(sun) && defined(sparc) */ +/* Marc Ullman, Stanford University Nov. 1 1989 */ +#if defined(sun) && (TARGET == SUN4) +/* Sparc (Sun 4) macros */ +#undef relocation_info +#define relocation_info reloc_info_sparc +#define RELOC_ADDRESS(r) ((r)->r_address) +#define RELOC_EXTERN_P(r) ((r)->r_extern) +#define RELOC_TYPE(r) ((r)->r_index) +#define RELOC_SYMBOL(r) ((r)->r_index) +#define RELOC_MEMORY_SUB_P(r) 0 +#define RELOC_MEMORY_ADD_P(r) 0 +#define RELOC_ADD_EXTRA(r) ((r)->r_addend) +#define RELOC_PCREL_P(r) \ + ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) +#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type]) +#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type]) +#define RELOC_TARGET_BITPOS(r) 0 +#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type]) + +/* Note that these are very dependent on the order of the enums in + enum reloc_type (in a.out.h); if they change the following must be + changed */ +/* Also note that the last few may be incorrect; I have no information */ +static int reloc_target_rightshift[] = { + 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, +}; +static int reloc_target_size[] = { + 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; +static int reloc_target_bitsize[] = { + 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, +}; + +#define MAX_ALIGNMENT (sizeof (double)) +#endif + +/* Default macros */ +#ifndef RELOC_ADDRESS +#define RELOC_ADDRESS(r) ((r)->r_address) +#define RELOC_EXTERN_P(r) ((r)->r_extern) +#define RELOC_TYPE(r) ((r)->r_symbolnum) +#define RELOC_SYMBOL(r) ((r)->r_symbolnum) +#define RELOC_MEMORY_SUB_P(r) 0 +#define RELOC_MEMORY_ADD_P(r) 1 +#undef RELOC_ADD_EXTRA +#define RELOC_PCREL_P(r) ((r)->r_pcrel) +#define RELOC_VALUE_RIGHTSHIFT(r) 0 +#define RELOC_TARGET_SIZE(r) ((r)->r_length) +#define RELOC_TARGET_BITPOS(r) 0 +#define RELOC_TARGET_BITSIZE(r) 32 +#endif + +#ifndef MAX_ALIGNMENT +#define MAX_ALIGNMENT (sizeof (int)) +#endif + +#ifdef nounderscore +#define LPREFIX '.' +#else +#define LPREFIX 'L' +#endif + +#ifndef TEXT_START +#define TEXT_START(x) N_TXTADDR(x) +#endif + +/* Special global symbol types understood by GNU LD. */ + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. + + So, for example, the following two lines placed in an assembler + input file would result in an object file which would direct gnu ld + to resolve all references to symbol "foo" as references to symbol + "bar". + + .stabs "_foo",11,0,0,0 + .stabs "_bar",1,0,0,0 + + Note that (11 == (N_INDR | N_EXT)) and (1 == (N_UNDF | N_EXT)). */ + +#ifndef N_INDR +#define N_INDR 0xa +#endif + +/* The following symbols refer to set elements. These are expected + only in input to the loader; they should not appear in loader + output (unless relocatable output is requested). To be recognized + by the loader, the input symbols must have their N_EXT bit set. + All the N_SET[ATDB] symbols with the same name form one set. The + loader collects all of these elements at load time and outputs a + vector for each name. + Space (an array of 32 bit words) is allocated for the set in the + data section, and the n_value field of each set element value is + stored into one word of the array. + The first word of the array is the length of the set (number of + elements). The last word of the vector is set to zero for possible + use by incremental loaders. The array is ordered by the linkage + order; the first symbols which the linker encounters will be first + in the array. + + In C syntax this looks like: + + struct set_vector { + unsigned int length; + unsigned int vector[length]; + unsigned int always_zero; + }; + + Before being placed into the array, each element is relocated + according to its type. This allows the loader to create an array + of pointers to objects automatically. N_SETA type symbols will not + be relocated. + + 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. + + For the purposes of determining whether or not to load in a library + file, set element definitions are not considered "real + definitions"; they will not cause the loading of a library + member. + + If relocatable output is requested, none of this processing is + done. The symbols are simply relocated and passed through to the + output file. + + So, for example, the following three lines of assembler code + (whether in one file or scattered between several different ones) + will produce a three element vector (total length is five words; + see above), referenced by the symbol "_xyzzy", which will have the + addresses of the routines _init1, _init2, and _init3. + + *NOTE*: If symbolic addresses are used in the n_value field of the + defining .stabs, those symbols must be defined in the same file as + that containing the .stabs. + + .stabs "_xyzzy",23,0,0,_init1 + .stabs "_xyzzy",23,0,0,_init2 + .stabs "_xyzzy",23,0,0,_init3 + + Note that (23 == (N_SETT | N_EXT)). */ + +#ifndef N_SETA +#define N_SETA 0x14 /* Absolute set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETT +#define N_SETT 0x16 /* Text set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETD +#define N_SETD 0x18 /* Data set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETB +#define N_SETB 0x1A /* Bss set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +/* Macros dealing with the set element symbols defined in a.out.h */ +#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT)) +#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS) + +#ifndef N_SETV +#define N_SETV 0x1C /* Pointer to set vector in data area. */ +#endif /* This is output from LD. */ + +/* If a this type of symbol is encountered, its name is a warning + message to print each time the symbol referenced by the next symbol + table entry is referenced. + + This feature may be used to allow backwards compatibility with + certain functions (eg. gets) but to discourage programmers from + their use. + + So if, for example, you wanted to have ld print a warning whenever + the function "gets" was used in their C program, you would add the + following to the assembler file in which gets is defined: + + .stabs "Obsolete function \"gets\" referenced",30,0,0,0 + .stabs "_gets",1,0,0,0 + + These .stabs do not necessarily have to be in the same file as the + gets function, they simply must exist somewhere in the compilation. */ + +#ifndef N_WARNING +#define N_WARNING 0x1E /* Warning message to print if symbol + included */ +#endif /* This is input to ld */ + +#ifndef __GNU_STAB__ + +/* Line number for the data section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_DSLINE +#define N_DSLINE (N_SLINE+N_DATA-N_TEXT) +#endif + +/* Line number for the bss section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_BSLINE +#define N_BSLINE (N_SLINE+N_BSS-N_TEXT) +#endif + +#endif /* not __GNU_STAB__ */ + +/* Symbol table */ + +/* Global symbol data is recorded in these structures, + one for each global symbol. + They are found via hashing in 'symtab', which points to a vector of buckets. + Each bucket is a chain of these structures through the link field. */ + +typedef + struct glosym + { + /* Pointer to next symbol in this symbol's hash bucket. */ + struct glosym *link; + /* Name of this symbol. */ + char *name; + /* Value of this symbol as a global symbol. */ + long value; + /* Chain of external 'nlist's in files for this symbol, both defs + and refs. */ + struct nlist *refs; + /* Any warning message that might be associated with this symbol + from an N_WARNING symbol encountered. */ + char *warning; + /* Nonzero means definitions of this symbol as common have been seen, + and the value here is the largest size specified by any of them. */ + int max_common_size; + /* For relocatable_output, records the index of this global sym in the + symbol table to be written, with the first global sym given index 0.*/ + int def_count; + /* Nonzero means a definition of this global symbol is known to exist. + Library members should not be loaded on its account. */ + char defined; + /* Nonzero means a reference to this global symbol has been seen + in a file that is surely being loaded. + A value higher than 1 is the n_type code for the symbol's + definition. */ + char referenced; + /* A count of the number of undefined references printed for a + specific symbol. If a symbol is unresolved at the end of + digest_symbols (and the loading run is supposed to produce + relocatable output) do_file_warnings keeps track of how many + unresolved reference error messages have been printed for + each symbol here. When the number hits MAX_UREFS_PRINTED, + messages stop. */ + unsigned char undef_refs; + /* 1 means that this symbol has multiple definitions. 2 means + that it has multiple definitions, and some of them are set + elements, one of which has been printed out already. */ + unsigned char multiply_defined; + /* Nonzero means print a message at all refs or defs of this symbol */ + char trace; + } + symbol; + +/* Demangler for C++. */ +extern char *cplus_demangle (); + +/* Demangler function to use. */ +char *(*demangler)() = NULL; + +/* Number of buckets in symbol hash table */ +#define TABSIZE 1009 + +/* The symbol hash table: a vector of TABSIZE pointers to struct glosym. */ +symbol *symtab[TABSIZE]; + +/* Number of symbols in symbol hash table. */ +int num_hash_tab_syms = 0; + +/* Count the number of nlist entries that are for local symbols. + This count and the three following counts + are incremented as as symbols are entered in the symbol table. */ +int local_sym_count; + +/* Count number of nlist entries that are for local symbols + whose names don't start with L. */ +int non_L_local_sym_count; + +/* Count the number of nlist entries for debugger info. */ +int debugger_sym_count; + +/* Count the number of global symbols referenced and not defined. */ +int undefined_global_sym_count; + +/* Count the number of global symbols multiply defined. */ +int multiple_def_count; + +/* Count the number of defined global symbols. + Each symbol is counted only once + regardless of how many different nlist entries refer to it, + since the output file will need only one nlist entry for it. + This count is computed by `digest_symbols'; + it is undefined while symbols are being loaded. */ +int defined_global_sym_count; + +/* Count the number of symbols defined through common declarations. + This count is kept in symdef_library, linear_library, and + enter_global_ref. It is incremented when the defined flag is set + in a symbol because of a common definition, and decremented when + the symbol is defined "for real" (ie. by something besides a common + definition). */ +int common_defined_global_count; + +/* Count the number of set element type symbols and the number of + separate vectors which these symbols will fit into. See the + GNU a.out.h for more info. + This count is computed by 'enter_file_symbols' */ +int set_symbol_count; +int set_vector_count; + +/* Define a linked list of strings which define symbols which should + be treated as set elements even though they aren't. Any symbol + with a prefix matching one of these should be treated as a set + element. + + This is to make up for deficiencies in many assemblers which aren't + willing to pass any stabs through to the loader which they don't + understand. */ +struct string_list_element { + char *str; + struct string_list_element *next; +}; + +struct string_list_element *set_element_prefixes; + +/* Count the number of definitions done indirectly (ie. done relative + to the value of some other symbol. */ +int global_indirect_count; + +/* Count the number of warning symbols encountered. */ +int warning_count; + +/* Total number of symbols to be written in the output file. + Computed by digest_symbols from the variables above. */ +int nsyms; + + +/* Nonzero means ptr to symbol entry for symbol to use as start addr. + -e sets this. */ +symbol *entry_symbol; + +symbol *edata_symbol; /* the symbol _edata */ +symbol *etext_symbol; /* the symbol _etext */ +symbol *end_symbol; /* the symbol _end */ + +/* Each input file, and each library member ("subfile") being loaded, + has a `file_entry' structure for it. + + For files specified by command args, these are contained in the vector + which `file_table' points to. + + For library members, they are dynamically allocated, + and chained through the `chain' field. + The chain is found in the `subfiles' field of the `file_entry'. + The `file_entry' objects for the members have `superfile' fields pointing + to the one for the library. */ + +struct file_entry { + /* Name of this file. */ + char *filename; + /* Name to use for the symbol giving address of text start */ + /* Usually the same as filename, but for a file spec'd with -l + this is the -l switch itself rather than the filename. */ + char *local_sym_name; + + /* Describe the layout of the contents of the file */ + + /* The file's a.out header. */ + struct exec header; + /* Offset in file of GDB symbol segment, or 0 if there is none. */ + int symseg_offset; + + /* Describe data from the file loaded into core */ + + /* Symbol table of the file. */ + struct nlist *symbols; + /* Size in bytes of string table. */ + int string_size; + /* Pointer to the string table. + The string table is not kept in core all the time, + but when it is in core, its address is here. */ + char *strings; + + /* Next two used only if `relocatable_output' or if needed for */ + /* output of undefined reference line numbers. */ + + /* Text reloc info saved by `write_text' for `coptxtrel'. */ + struct relocation_info *textrel; + /* Data reloc info saved by `write_data' for `copdatrel'. */ + struct relocation_info *datarel; + + /* Relation of this file's segments to the output file */ + + /* Start of this file's text seg in the output file core image. */ + int text_start_address; + /* Start of this file's data seg in the output file core image. */ + int data_start_address; + /* Start of this file's bss seg in the output file core image. */ + int bss_start_address; + /* Offset in bytes in the output file symbol table + of the first local symbol for this file. Set by `write_file_symbols'. */ + int local_syms_offset; + + /* For library members only */ + + /* For a library, points to chain of entries for the library members. */ + struct file_entry *subfiles; + /* For a library member, offset of the member within the archive. + Zero for files that are not library members. */ + int starting_offset; + /* Size of contents of this file, if library member. */ + int total_size; + /* For library member, points to the library's own entry. */ + struct file_entry *superfile; + /* For library member, points to next entry for next member. */ + struct file_entry *chain; + + /* 1 if file is a library. */ + char library_flag; + + /* 1 if file's header has been read into this structure. */ + char header_read_flag; + + /* 1 means search a set of directories for this file. */ + char search_dirs_flag; + + /* 1 means this is base file of incremental load. + Do not load this file's text or data. + Also default text_start to after this file's bss. */ + char just_syms_flag; +}; + +/* Vector of entries for input files specified by arguments. + These are all the input files except for members of specified libraries. */ +struct file_entry *file_table; + +/* Length of that vector. */ +int number_of_files; + +/* When loading the text and data, we can avoid doing a close + and another open between members of the same library. + + These two variables remember the file that is currently open. + Both are zero if no file is open. + + See `each_file' and `file_close'. */ + +struct file_entry *input_file; +int input_desc; + +/* The name of the file to write; "a.out" by default. */ + +char *output_filename; + +/* Descriptor for writing that file with `mywrite'. */ + +int outdesc; + +/* Header for that file (filled in by `write_header'). */ + +struct exec outheader; + +#ifdef COFF_ENCAPSULATE +struct coffheader coffheader; +int need_coff_header; +#endif + +/* The following are computed by `digest_symbols'. */ + +int text_size; /* total size of text of all input files. */ +int data_size; /* total size of data of all input files. */ +int bss_size; /* total size of bss of all input files. */ +int text_reloc_size; /* total size of text relocation of all input files. */ +int data_reloc_size; /* total size of data relocation of all input */ + /* files. */ + +/* Specifications of start and length of the area reserved at the end + of the text segment for the set vectors. Computed in 'digest_symbols' */ +int set_sect_start; +int set_sect_size; + +/* Pointer for in core storage for the above vectors, before they are + written. */ +unsigned long *set_vectors; + +/* Amount of cleared space to leave between the text and data segments. */ + +int text_pad; + +/* Amount of bss segment to include as part of the data segment. */ + +int data_pad; + +/* 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 { + int symbol_name_string_index; + int library_member_offset; +}; + +/* Record most of the command options. */ + +/* Address we assume the text section will be loaded at. + We relocate symbols and text and data for this, but we do not + write any padding in the output file for it. */ +int text_start; + +/* Offset of default entry-pc within the text section. */ +int entry_offset; + +/* Address we decide the data section will be loaded at. */ +int data_start; + +/* `text-start' address is normally this much plus a page boundary. + This is not a user option; it is fixed for each system. */ +int text_start_alignment; + +/* Nonzero if -T was specified in the command line. + This prevents text_start from being set later to default values. */ +int T_flag_specified; + +/* Nonzero if -Tdata was specified in the command line. + This prevents data_start from being set later to default values. */ +int Tdata_flag_specified; + +/* Size to pad data section up to. + We simply increase the size of the data section, padding with zeros, + and reduce the size of the bss section to match. */ +int specified_data_size; + +/* Magic number to use for the output file, set by switch. */ +int magic; + +/* Nonzero means print names of input files as processed. */ +int trace_files; + +/* Which symbols should be stripped (omitted from the output): + none, all, or debugger symbols. */ +enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols; + +/* Which local symbols should be omitted: + none, all, or those starting with L. + This is irrelevant if STRIP_NONE. */ +enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals; + +/* Do we want to pad the text to a page boundary? */ +int padtext; + +/* 1 => write load map. */ +int write_map; + +/* 1 => write relocation into output file so can re-input it later. */ +int relocatable_output; + +/* 1 => assign space to common symbols even if `relocatable_output'. */ +int force_common_definition; + +/* Standard directories to search for files specified by -l. */ +char *standard_search_dirs[] = +#ifdef STANDARD_SEARCH_DIRS + {STANDARD_SEARCH_DIRS}; +#else +#ifdef NON_NATIVE + {"/usr/local/lib/gnu"}; +#else + {"/lib", "/usr/lib", "/usr/local/lib"}; +#endif +#endif + +/* Actual vector of directories to search; + this contains those specified with -L plus the standard ones. */ +char **search_dirs; + +/* Length of the vector `search_dirs'. */ +int n_search_dirs; + +/* Non zero means to create the output executable. */ +/* Cleared by nonfatal errors. */ +int make_executable; + +/* Force the executable to be output, even if there are non-fatal + errors */ +int force_executable; + +/* 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; +int cl_refs_allocated; + +void bcopy (), bzero (); +int malloc (), realloc (); +#ifndef alloca +int alloca (); +#endif +int free (); + +int xmalloc (); +int xrealloc (); +void fatal (); +void fatal_with_file (); +void perror_name (); +void perror_file (); +void error (); + +void digest_symbols (); +void print_symbols (); +void load_symbols (); +void decode_command (); +void list_undefined_symbols (); +void list_unresolved_references (); +void write_output (); +void write_header (); +void write_text (); +void read_file_relocation (); +void write_data (); +void write_rel (); +void write_syms (); +void write_symsegs (); +void mywrite (); +void symtab_init (); +void padfile (); +char *concat (); +char *get_file_name (); +symbol *getsym (), *getsym_soft (); + +int +main (argc, argv) + char **argv; + int argc; +{ +/* Added this to stop ld core-dumping on very large .o files. */ +#ifdef RLIMIT_STACK + /* Get rid of any avoidable limit on stack size. */ + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* RLIMIT_STACK */ + + page_size = getpagesize (); + progname = argv[0]; + + /* Clear the cumulative info on the output file. */ + + text_size = 0; + data_size = 0; + bss_size = 0; + text_reloc_size = 0; + data_reloc_size = 0; + + data_pad = 0; + text_pad = 0; + + /* Initialize the data about options. */ + + specified_data_size = 0; + strip_symbols = STRIP_NONE; + trace_files = 0; + discard_locals = DISCARD_NONE; + padtext = 0; + entry_symbol = 0; + write_map = 0; + relocatable_output = 0; + force_common_definition = 0; + T_flag_specified = 0; + Tdata_flag_specified = 0; + magic = DEFAULT_MAGIC; + make_executable = 1; + force_executable = 0; + set_element_prefixes = 0; + + /* Initialize the cumulative counts of symbols. */ + + local_sym_count = 0; + non_L_local_sym_count = 0; + debugger_sym_count = 0; + undefined_global_sym_count = 0; + set_symbol_count = 0; + set_vector_count = 0; + global_indirect_count = 0; + warning_count = 0; + multiple_def_count = 0; + common_defined_global_count = 0; + + /* 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 = 0; + + /* Completely decode ARGV. */ + + decode_command (argc, argv); + + /* Create the symbols `etext', `edata' and `end'. */ + + if (!relocatable_output) + symtab_init (); + + /* Determine whether to count the header as part of + the text size, and initialize the text size accordingly. + This depends on the kind of system and on the output format selected. */ + + N_SET_MAGIC (outheader, magic); +#ifdef INITIALIZE_HEADER + INITIALIZE_HEADER; +#endif + + text_size = sizeof (struct exec); +#ifdef COFF_ENCAPSULATE + if (relocatable_output == 0 && file_table[0].just_syms_flag == 0) + { + need_coff_header = 1; + /* set this flag now, since it will change the values of N_TXTOFF, etc */ + N_SET_FLAGS (outheader, N_FLAGS_COFF_ENCAPSULATE); + text_size += sizeof (struct coffheader); + } +#endif + + text_size -= N_TXTOFF (outheader); + + if (text_size < 0) + text_size = 0; + entry_offset = text_size; + + if (!T_flag_specified && !relocatable_output) + text_start = TEXT_START (outheader); + + /* The text-start address is normally this far past a page boundary. */ + text_start_alignment = text_start % page_size; + + /* Load symbols of all input files. + Also search all libraries and decide which library members to load. */ + + load_symbols (); + + /* Compute where each file's sections go, and relocate symbols. */ + + digest_symbols (); + + /* Print error messages for any missing symbols, for any warning + symbols, and possibly multiple definitions */ + + do_warnings (stderr); + + /* Print a map, if requested. */ + + if (write_map) print_symbols (stdout); + + /* Write the output file. */ + + if (make_executable || force_executable) + write_output (); + + exit (!make_executable); +} + +void decode_option (); + +/* Analyze a command line argument. + Return 0 if the argument is a filename. + Return 1 if the argument is a option complete in itself. + Return 2 if the argument is a option which uses an argument. + + Thus, the value is the number of consecutive arguments + that are part of options. */ + +int +classify_arg (arg) + register char *arg; +{ + if (*arg != '-') return 0; + switch (arg[1]) + { + case 'A': + case 'D': + case 'e': + case 'L': + case 'l': + case 'o': + case 'u': + case 'V': + case 'y': + if (arg[2]) + return 1; + return 2; + + case 'B': + if (! strcmp (&arg[2], "static")) + return 1; + + case 'T': + if (arg[2] == 0) + return 2; + if (! strcmp (&arg[2], "text")) + return 2; + if (! strcmp (&arg[2], "data")) + return 2; + return 1; + } + + return 1; +} + +/* Process the command arguments, + setting up file_table with an entry for each input file, + and setting variables according to the options. */ + +void +decode_command (argc, argv) + char **argv; + int argc; +{ + register int i; + register struct file_entry *p; + char *cp; + + number_of_files = 0; + output_filename = "a.out"; + + n_search_dirs = 0; + search_dirs = (char **) xmalloc (sizeof (char *)); + + /* First compute number_of_files so we know how long to make file_table. */ + /* Also process most options completely. */ + + for (i = 1; i < argc; i++) + { + register int code = classify_arg (argv[i]); + if (code) + { + if (i + code > argc) + fatal ("no argument following %s\n", argv[i]); + + decode_option (argv[i], argv[i+1]); + + if (argv[i][1] == 'l' || argv[i][1] == 'A') + number_of_files++; + + i += code - 1; + } + else + number_of_files++; + } + + if (!number_of_files) + fatal ("no input files", 0); + + p = file_table + = (struct file_entry *) xmalloc (number_of_files * sizeof (struct file_entry)); + bzero (p, number_of_files * sizeof (struct file_entry)); + + /* Now scan again and fill in file_table. */ + /* All options except -A and -l are ignored here. */ + + for (i = 1; i < argc; i++) + { + register int code = classify_arg (argv[i]); + + if (code) + { + char *string; + if (code == 2) + string = argv[i+1]; + else + string = &argv[i][2]; + + if (argv[i][1] == 'A') + { + if (p != file_table) + fatal ("-A specified before an input file other than the first"); + + p->filename = string; + p->local_sym_name = string; + p->just_syms_flag = 1; + p++; + } + if (argv[i][1] == 'l') + { + if (cp = rindex(string, '/')) + { + *cp++ = '\0'; + cp = concat (string, "/lib", cp); + p->filename = concat (cp, ".a", ""); + } + else + p->filename = concat ("lib", string, ".a"); + + p->local_sym_name = concat ("-l", string, ""); + p->search_dirs_flag = 1; + p++; + } + i += code - 1; + } + else + { + p->filename = argv[i]; + p->local_sym_name = argv[i]; + p++; + } + } + + /* Now check some option settings for consistency. */ + +#ifdef NMAGIC + if ((magic == ZMAGIC || magic == NMAGIC) +#else + if ((magic == ZMAGIC) +#endif + && (text_start - text_start_alignment) & (page_size - 1)) + fatal ("-T argument not multiple of page size, with sharable output", 0); + + /* Append the standard search directories to the user-specified ones. */ + { + int n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; + n_search_dirs += n; + search_dirs + = (char **) xrealloc (search_dirs, n_search_dirs * sizeof (char *)); + bcopy (standard_search_dirs, &search_dirs[n_search_dirs - n], + n * sizeof (char *)); + } +} + + +void +add_cmdline_ref (sp) + struct glosym *sp; +{ + struct glosym **ptr; + + for (ptr = cmdline_references; + ptr < cmdline_references + cl_refs_allocated && *ptr; + ptr++) + ; + + if (ptr >= cmdline_references + cl_refs_allocated - 1) + { + int diff = ptr - cmdline_references; + + cl_refs_allocated *= 2; + cmdline_references = (struct glosym **) + xrealloc (cmdline_references, + cl_refs_allocated * sizeof (struct glosym *)); + ptr = cmdline_references + diff; + } + + *ptr++ = sp; + *ptr = (struct glosym *) 0; +} + +int +set_element_prefixed_p (name) + char *name; +{ + struct string_list_element *p; + int i; + + for (p = set_element_prefixes; p; p = p->next) + { + for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++) + ; + + if (p->str[i] == '\0') + return 1; + } + return 0; +} + +int parse (); + +/* Record an option and arrange to act on it later. + ARG should be the following command argument, + which may or may not be used by this option. + + The `l' and `A' options are ignored here since they actually + specify input files. */ + +void +decode_option (swt, arg) + register char *swt, *arg; +{ + /* We get Bstatic from gcc on suns. */ + if (! strcmp (swt + 1, "Bstatic")) + return; + if (! strcmp (swt + 1, "Ttext")) + { + text_start = parse (arg, "%x", "invalid argument to -Ttext"); + T_flag_specified = 1; + return; + } + if (! strcmp (swt + 1, "Tdata")) + { + data_start = parse (arg, "%x", "invalid argument to -Tdata"); + Tdata_flag_specified = 1; + return; + } + if (! strcmp (swt + 1, "noinhibit-exec")) + { + force_executable = 1; + return; + } + + if (swt[2] != 0) + arg = &swt[2]; + + switch (swt[1]) + { + case 'A': + return; + + case 'D': + specified_data_size = parse (arg, "%x", "invalid argument to -D"); + return; + + case 'd': + force_common_definition = 1; + return; + + case 'e': + entry_symbol = getsym (arg); + if (!entry_symbol->defined && !entry_symbol->referenced) + undefined_global_sym_count++; + entry_symbol->referenced = 1; + add_cmdline_ref (entry_symbol); + return; + + case 'l': + /* If linking with libg++, use the C++ demangler. */ + if (arg != NULL && strcmp (arg, "g++") == 0) + demangler = cplus_demangle; + return; + + case 'L': + n_search_dirs++; + search_dirs + = (char **) xrealloc (search_dirs, n_search_dirs * sizeof (char *)); + search_dirs[n_search_dirs - 1] = arg; + return; + + case 'M': + write_map = 1; + return; + + case 'N': + magic = OMAGIC; + return; + +#ifdef NMAGIC + case 'n': + magic = NMAGIC; + return; +#endif + + case 'o': + output_filename = arg; + return; + + case 'p': + padtext = 1; + return; + + case 'r': + relocatable_output = 1; + magic = OMAGIC; + text_start = 0; + return; + + case 'S': + strip_symbols = STRIP_DEBUGGER; + return; + + case 's': + strip_symbols = STRIP_ALL; + return; + + case 'T': + text_start = parse (arg, "%x", "invalid argument to -T"); + T_flag_specified = 1; + return; + + case 't': + trace_files = 1; + return; + + case 'u': + { + register symbol *sp = getsym (arg); + if (!sp->defined && !sp->referenced) + undefined_global_sym_count++; + sp->referenced = 1; + add_cmdline_ref (sp); + } + return; + + case 'V': + { + struct string_list_element *new + = (struct string_list_element *) + xmalloc (sizeof (struct string_list_element)); + + new->str = arg; + new->next = set_element_prefixes; + set_element_prefixes = new; + return; + } + + case 'X': + discard_locals = DISCARD_L; + return; + + case 'x': + discard_locals = DISCARD_ALL; + return; + + case 'y': + { + register symbol *sp = getsym (&swt[2]); + sp->trace = 1; + } + return; + + case 'z': + magic = ZMAGIC; + return; + + default: + fatal ("invalid command option `%s'", swt); + } +} + +/** Convenient functions for operating on one or all files being */ + /** loaded. */ +void print_file_name (); + +/* Call FUNCTION on each input file entry. + Do not call for entries for libraries; + instead, call once for each library member that is being loaded. + + FUNCTION receives two arguments: the entry, and ARG. */ + +void +each_file (function, arg) + register void (*function)(); + register int arg; +{ + register int i; + + for (i = 0; i < number_of_files; i++) + { + register struct file_entry *entry = &file_table[i]; + if (entry->library_flag) + { + register struct file_entry *subentry = entry->subfiles; + for (; subentry; subentry = subentry->chain) + (*function) (subentry, arg); + } + else + (*function) (entry, arg); + } +} + +/* Call FUNCTION on each input file entry until it returns a non-zero + value. Return this value. + Do not call for entries for libraries; + instead, call once for each library member that is being loaded. + + FUNCTION receives two arguments: the entry, and ARG. It must be a + function returning unsigned long (though this can probably be fudged). */ + +unsigned long +check_each_file (function, arg) + register unsigned long (*function)(); + register int arg; +{ + register int i; + register unsigned long return_val; + + for (i = 0; i < number_of_files; i++) + { + register struct file_entry *entry = &file_table[i]; + if (entry->library_flag) + { + register struct file_entry *subentry = entry->subfiles; + for (; subentry; subentry = subentry->chain) + if (return_val = (*function) (subentry, arg)) + return return_val; + } + else + if (return_val = (*function) (entry, arg)) + return return_val; + } + return 0; +} + +/* Like `each_file' but ignore files that were just for symbol definitions. */ + +void +each_full_file (function, arg) + register void (*function)(); + register int arg; +{ + register int i; + + for (i = 0; i < number_of_files; i++) + { + register struct file_entry *entry = &file_table[i]; + if (entry->just_syms_flag) + continue; + if (entry->library_flag) + { + register struct file_entry *subentry = entry->subfiles; + for (; subentry; subentry = subentry->chain) + (*function) (subentry, arg); + } + else + (*function) (entry, arg); + } +} + +/* Close the input file that is now open. */ + +void +file_close () +{ + close (input_desc); + input_desc = 0; + input_file = 0; +} + +/* Open the input file specified by 'entry', and return a descriptor. + The open file is remembered; if the same file is opened twice in a row, + a new open is not actually done. */ + +int +file_open (entry) + register struct file_entry *entry; +{ + register int desc; + + if (entry->superfile) + return file_open (entry->superfile); + + if (entry == input_file) + return input_desc; + + if (input_file) file_close (); + + if (entry->search_dirs_flag) + { + int i; + + for (i = 0; i < n_search_dirs; i++) + { + register char *string + = concat (search_dirs[i], "/", entry->filename); + desc = open (string, O_RDONLY, 0); + if (desc > 0) + { + entry->filename = string; + entry->search_dirs_flag = 0; + break; + } + free (string); + } + } + else + desc = open (entry->filename, O_RDONLY, 0); + + if (desc > 0) + { + input_file = entry; + input_desc = desc; + return desc; + } + + perror_file (entry); + /* NOTREACHED */ +} + +/* Print the filename of ENTRY on OUTFILE (a stdio stream), + and then a newline. */ + +void +prline_file_name (entry, outfile) + struct file_entry *entry; + FILE *outfile; +{ + print_file_name (entry, outfile); + fprintf (outfile, "\n"); +} + +/* Print the filename of ENTRY on OUTFILE (a stdio stream). */ + +void +print_file_name (entry, outfile) + struct file_entry *entry; + FILE *outfile; +{ + if (entry->superfile) + { + print_file_name (entry->superfile, outfile); + fprintf (outfile, "(%s)", entry->filename); + } + else + fprintf (outfile, "%s", entry->filename); +} + +/* Return the filename of entry as a string (malloc'd for the purpose) */ + +char * +get_file_name (entry) + struct file_entry *entry; +{ + char *result, *supfile; + 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); + } + else + { + result = (char *) xmalloc (strlen (entry->filename) + 1); + strcpy (result, entry->filename); + } + return result; +} + +/* Medium-level input routines for rel files. */ + +/* Read a file's header into the proper place in the file_entry. + DESC 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; +{ + register int len; + struct exec *loc = (struct exec *) &entry->header; + + lseek (desc, entry->starting_offset, 0); +#ifdef COFF_ENCAPSULATE + if (entry->just_syms_flag) + lseek (desc, sizeof(coffheader), 1); +#endif + len = read (desc, loc, sizeof (struct exec)); + if (len != sizeof (struct exec)) + fatal_with_file ("failure reading header of ", entry); + if (N_BADMAG (*loc)) + fatal_with_file ("bad magic number in ", entry); + + entry->header_read_flag = 1; +} + +/* 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 the symbol table, + but don't read the contents of the string table. */ + +void +read_entry_symbols (desc, entry) + struct file_entry *entry; + int desc; +{ + int str_size; + + if (!entry->header_read_flag) + read_header (desc, entry); + + entry->symbols = (struct nlist *) xmalloc (entry->header.a_syms); + + lseek (desc, N_SYMOFF (entry->header) + entry->starting_offset, 0); + if (entry->header.a_syms != read (desc, entry->symbols, entry->header.a_syms)) + fatal_with_file ("premature end of file in symbols of ", entry); + + lseek (desc, N_STROFF (entry->header) + entry->starting_offset, 0); + if (sizeof str_size != read (desc, &str_size, sizeof str_size)) + fatal_with_file ("bad string table size in ", entry); + + entry->string_size = str_size; +} + +/* Read the string table of file ENTRY into core. + Assume it is already open, on descriptor DESC. + Also record whether a GDB symbol segment follows the string table. */ + +void +read_entry_strings (desc, entry) + struct file_entry *entry; + int desc; +{ + int buffer; + + if (!entry->header_read_flag) + read_header (desc, entry); + + lseek (desc, N_STROFF (entry->header) + entry->starting_offset, 0); + if (entry->string_size != read (desc, entry->strings, entry->string_size)) + fatal_with_file ("premature end of file in strings of ", entry); + + /* While we are here, see if the file has a symbol segment at the end. + For a separate file, just try reading some more. + For a library member, compare current pos against total size. */ + if (entry->superfile) + { + if (entry->total_size == N_STROFF (entry->header) + entry->string_size) + return; + } + else + { + buffer = read (desc, &buffer, sizeof buffer); + if (buffer == 0) + return; + if (buffer != sizeof buffer) + fatal_with_file ("premature end of file in GDB symbol segment of ", entry); + } + /* Don't try to do anything with symsegs. */ + return; +#if 0 + /* eliminate warning of `statement not reached'. */ + entry->symseg_offset = N_STROFF (entry->header) + entry->string_size; +#endif +} + +/* Read in the symbols of all input files. */ + +void read_file_symbols (), read_entry_symbols (), read_entry_strings (); +void enter_file_symbols (), enter_global_ref (), search_library (); + +void +load_symbols () +{ + register int i; + + if (trace_files) fprintf (stderr, "Loading symbols:\n\n"); + + for (i = 0; i < number_of_files; i++) + { + register struct file_entry *entry = &file_table[i]; + read_file_symbols (entry); + } + + if (trace_files) fprintf (stderr, "\n"); +} + +/* If ENTRY is a rel file, read its symbol and string sections into core. + If it is a library, search it and load the appropriate members + (which means calling this function recursively on those members). */ + +void +read_file_symbols (entry) + register struct file_entry *entry; +{ + register int desc; + register int len; + struct exec hdr; + + desc = file_open (entry); + +#ifdef COFF_ENCAPSULATE + if (entry->just_syms_flag) + lseek (desc, sizeof(coffheader),0); +#endif + + len = read (desc, &hdr, sizeof hdr); + if (len != sizeof hdr) + fatal_with_file ("failure reading header of ", entry); + + if (!N_BADMAG (hdr)) + { + read_entry_symbols (desc, entry); + entry->strings = (char *) alloca (entry->string_size); + read_entry_strings (desc, entry); + enter_file_symbols (entry); + entry->strings = 0; + } + else + { + char armag[SARMAG]; + + lseek (desc, 0, 0); + if (SARMAG != read (desc, armag, SARMAG) || strncmp (armag, ARMAG, SARMAG)) + fatal_with_file ("malformed input file (not rel or archive) ", entry); + entry->library_flag = 1; + search_library (desc, entry); + } + + file_close (); +} + +/* Enter the external symbol defs and refs of ENTRY in the hash table. */ + +void +enter_file_symbols (entry) + struct file_entry *entry; +{ + register struct nlist + *p, + *end = entry->symbols + entry->header.a_syms / sizeof (struct nlist); + + if (trace_files) prline_file_name (entry, stderr); + + for (p = entry->symbols; p < end; p++) + { + if (p->n_type == (N_SETV | N_EXT)) continue; + if (set_element_prefixes + && set_element_prefixed_p (p->n_un.n_strx + entry->strings)) + p->n_type += (N_SETA - N_ABS); + + if (SET_ELEMENT_P (p->n_type)) + { + set_symbol_count++; + if (!relocatable_output) + enter_global_ref (p, p->n_un.n_strx + entry->strings, entry); + } + else if (p->n_type == N_WARNING) + { + char *name = p->n_un.n_strx + entry->strings; + + /* Grab the next entry. */ + p++; + if (p->n_type != (N_UNDF | N_EXT)) + { + fprintf (stderr, "%s: Warning symbol found in %s without external reference following.\n", + progname, entry->filename); + make_executable = 0; + p--; /* Process normally. */ + } + else + { + symbol *sp; + char *sname = p->n_un.n_strx + entry->strings; + /* Deal with the warning symbol. */ + enter_global_ref (p, p->n_un.n_strx + entry->strings, entry); + sp = getsym (sname); + sp->warning = (char *) xmalloc (strlen(name) + 1); + strcpy (sp->warning, name); + warning_count++; + } + } + else if (p->n_type & N_EXT) + enter_global_ref (p, p->n_un.n_strx + entry->strings, entry); + else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT))) + { + if ((p->n_un.n_strx + entry->strings)[0] != LPREFIX) + non_L_local_sym_count++; + local_sym_count++; + } + else debugger_sym_count++; + } + + /* Count one for the local symbol that we generate, + whose name is the file's name (usually) and whose address + is the start of the file's text. */ + + local_sym_count++; + non_L_local_sym_count++; +} + +/* Enter one global symbol in the hash table. + NLIST_P points to the `struct nlist' read from the file + that describes the global symbol. NAME is the symbol's name. + ENTRY is the file entry for the file the symbol comes from. + + The `struct nlist' is modified by placing it on a chain of + all such structs that refer to the same global symbol. + This chain starts in the `refs' field of the symbol table entry + and is chained through the `n_name'. */ + +void +enter_global_ref (nlist_p, name, entry) + register struct nlist *nlist_p; + char *name; + struct file_entry *entry; +{ + register symbol *sp = getsym (name); + register int type = nlist_p->n_type; + int oldref = sp->referenced; + int olddef = sp->defined; + int com = sp->defined && sp->max_common_size; + + nlist_p->n_un.n_name = (char *) sp->refs; + sp->refs = nlist_p; + + sp->referenced = 1; + if (type != (N_UNDF | N_EXT) || nlist_p->n_value) + { + if (!sp->defined || sp->defined == (N_UNDF | N_EXT)) + sp->defined = type; + + if (oldref && !olddef) + /* It used to be undefined and we're defining it. */ + undefined_global_sym_count--; + + if (!olddef && type == (N_UNDF | N_EXT) && nlist_p->n_value) + { + /* First definition and it's common. */ + common_defined_global_count++; + sp->max_common_size = nlist_p->n_value; + } + else if (com && type != (N_UNDF | N_EXT)) + { + /* It used to be common and we're defining it as + something else. */ + common_defined_global_count--; + sp->max_common_size = 0; + } + else if (com && type == (N_UNDF | N_EXT) + && sp->max_common_size < nlist_p->n_value) + /* It used to be common and this is a new common entry to + which we need to pay attention. */ + sp->max_common_size = nlist_p->n_value; + + /* Are we defining it as a set element? */ + if (SET_ELEMENT_P (type) && (!olddef || com)) + set_vector_count++; + /* As an indirection? */ + else if (type == (N_INDR | N_EXT)) + { + /* Indirect symbols value should be modified to point + a symbol being equivalenced to. */ + nlist_p->n_value + = (unsigned int) getsym ((nlist_p + 1)->n_un.n_strx + + entry->strings); + if ((symbol *) nlist_p->n_value == sp) + { + /* Somebody redefined a symbol to be itself. */ + fprintf (stderr, "%s: Symbol %s indirected to itself.\n", + entry->filename, name); + /* Rewrite this symbol as being a global text symbol + with value 0. */ + nlist_p->n_type = sp->defined = N_TEXT | N_EXT; + nlist_p->n_value = 0; + /* Don't make the output executable. */ + make_executable = 0; + } + else + global_indirect_count++; + } + } + else + if (!oldref) +#ifndef DOLLAR_KLUDGE + undefined_global_sym_count++; +#else + { + if (entry->superfile && type == (N_UNDF | N_EXT) && name[1] == '$') + { + /* This is an (ISI?) $-conditional; skip it */ + sp->referenced = 0; + if (sp->trace) + { + fprintf (stderr, "symbol %s is a $-conditional ignored in ", sp->name); + print_file_name (entry, stderr); + fprintf (stderr, "\n"); + } + return; + } + else + undefined_global_sym_count++; + } +#endif + + if (sp == end_symbol && entry->just_syms_flag && !T_flag_specified) + text_start = nlist_p->n_value; + + if (sp->trace) + { + register char *reftype; + switch (type & N_TYPE) + { + case N_UNDF: + if (nlist_p->n_value) + reftype = "defined as common"; + else reftype = "referenced"; + break; + + case N_ABS: + reftype = "defined as absolute"; + break; + + case N_TEXT: + reftype = "defined in text section"; + break; + + case N_DATA: + reftype = "defined in data section"; + break; + + case N_BSS: + reftype = "defined in BSS section"; + break; + + case N_SETT: + reftype = "is a text set element"; + break; + + case N_SETD: + reftype = "is a data set element"; + break; + + case N_SETB: + reftype = "is a BSS set element"; + break; + + case N_SETA: + reftype = "is an absolute set element"; + break; + + case N_SETV: + reftype = "defined in data section as vector"; + break; + + case N_INDR: + reftype = (char *) alloca (23 + + strlen ((nlist_p + 1)->n_un.n_strx + + entry->strings)); + sprintf (reftype, "defined equivalent to %s", + (nlist_p + 1)->n_un.n_strx + entry->strings); + break; + +#ifdef sequent + case N_SHUNDF: + reftype = "shared undf"; + break; + +/* These conflict with cases above. + case N_SHDATA: + reftype = "shared data"; + break; + + case N_SHBSS: + reftype = "shared BSS"; + break; +*/ + default: + reftype = "I don't know this type"; + break; +#endif + } + + fprintf (stderr, "symbol %s %s in ", sp->name, reftype); + print_file_name (entry, stderr); + fprintf (stderr, "\n"); + } +} + +/* This return 0 if the given file entry's symbol table does *not* + contain the nlist point entry, and it returns the files entry + pointer (cast to unsigned long) if it does. */ + +unsigned long +contains_symbol (entry, n_ptr) + struct file_entry *entry; + register struct nlist *n_ptr; +{ + if (n_ptr >= entry->symbols && + n_ptr < (entry->symbols + + (entry->header.a_syms / sizeof (struct nlist)))) + return (unsigned long) entry; + return 0; +} + + +/* Searching libraries */ + +struct file_entry *decode_library_subfile (); +void linear_library (), symdef_library (); + +/* Search the library ENTRY, already open on descriptor DESC. + 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; + struct file_entry *entry; +{ + int member_length; + register char *name; + register struct file_entry *subentry; + + if (!undefined_global_sym_count) return; + + /* Examine its first member, which starts SARMAG bytes in. */ + subentry = decode_library_subfile (desc, entry, SARMAG, &member_length); + if (!subentry) return; + + name = subentry->filename; + free (subentry); + + /* Search via __.SYMDEF if that exists, else linearly. */ + + if (!strcmp (name, "__.SYMDEF")) + symdef_library (desc, entry, member_length); + else + linear_library (desc, 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. + SUBFILE_OFFSET is the byte index in the library of this member's header. + We store the length of the member into *LENGTH_LOC. */ + +struct file_entry * +decode_library_subfile (desc, library_entry, subfile_offset, length_loc) + int desc; + struct file_entry *library_entry; + int subfile_offset; + int *length_loc; +{ + int bytes_read; + register int namelen; + int member_length; + register char *name; + struct ar_hdr hdr1; + register struct file_entry *subentry; + + lseek (desc, subfile_offset, 0); + + bytes_read = read (desc, &hdr1, sizeof hdr1); + if (!bytes_read) + return 0; /* end of archive */ + + if (sizeof hdr1 != bytes_read) + fatal_with_file ("malformed library archive ", library_entry); + + if (sscanf (hdr1.ar_size, "%d", &member_length) != 1) + fatal_with_file ("malformatted header of archive member in ", library_entry); + + subentry = (struct file_entry *) xmalloc (sizeof (struct file_entry)); + bzero (subentry, sizeof (struct file_entry)); + + for (namelen = 0; + namelen < sizeof hdr1.ar_name + && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' ' + && hdr1.ar_name[namelen] != '/'; + namelen++); + + name = (char *) xmalloc (namelen+1); + strncpy (name, hdr1.ar_name, namelen); + name[namelen] = 0; + + subentry->filename = name; + subentry->local_sym_name = name; + subentry->symbols = 0; + subentry->strings = 0; + subentry->subfiles = 0; + subentry->starting_offset = subfile_offset + sizeof hdr1; + subentry->superfile = library_entry; + subentry->library_flag = 0; + subentry->header_read_flag = 0; + subentry->just_syms_flag = 0; + subentry->chain = 0; + subentry->total_size = member_length; + + (*length_loc) = member_length; + + return subentry; +} + +int subfile_wanted_p (); + +/* Search a library that has a __.SYMDEF member. + DESC 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. */ + +void +symdef_library (desc, entry, member_length) + int desc; + struct file_entry *entry; + int member_length; +{ + int *symdef_data = (int *) xmalloc (member_length); + register struct symdef *symdef_base; + char *sym_name_base; + int number_of_symdefs; + int length_of_strings; + int not_finished; + int bytes_read; + register int i; + struct file_entry *prev = 0; + int prev_offset = 0; + + bytes_read = read (desc, symdef_data, member_length); + if (bytes_read != member_length) + fatal_with_file ("malformatted __.SYMDEF in ", entry); + + number_of_symdefs = *symdef_data / sizeof (struct symdef); + if (number_of_symdefs < 0 || + number_of_symdefs * sizeof (struct symdef) + 2 * sizeof (int) > member_length) + fatal_with_file ("malformatted __.SYMDEF in ", entry); + + symdef_base = (struct symdef *) (symdef_data + 1); + length_of_strings = *(int *) (symdef_base + number_of_symdefs); + + if (length_of_strings < 0 + || number_of_symdefs * sizeof (struct symdef) + length_of_strings + + 2 * sizeof (int) > member_length) + fatal_with_file ("malformatted __.SYMDEF in ", entry); + + sym_name_base = sizeof (int) + (char *) (symdef_base + number_of_symdefs); + + /* Check all the string indexes for validity. */ + + for (i = 0; i < number_of_symdefs; i++) + { + register int index = symdef_base[i].symbol_name_string_index; + if (index < 0 || index >= length_of_strings + || (index && *(sym_name_base + index - 1))) + fatal_with_file ("malformatted __.SYMDEF in ", entry); + } + + /* Search the symdef data for members to load. + Do this until one whole pass finds nothing to load. */ + + not_finished = 1; + while (not_finished) + { + not_finished = 0; + + /* Scan all the symbols mentioned in the symdef for ones that we need. + Load the library members that contain such symbols. */ + + for (i = 0; + (i < number_of_symdefs + && (undefined_global_sym_count || common_defined_global_count)); + i++) + if (symdef_base[i].symbol_name_string_index >= 0) + { + register symbol *sp; + + sp = getsym_soft (sym_name_base + + symdef_base[i].symbol_name_string_index); + + /* If we find a symbol that appears to be needed, think carefully + about the archive member that the symbol is in. */ + + /* + * Per Mike Karels' recommendation, we no longer load library + * files if the only reference(s) that would be satisfied are + * 'common' references. This prevents some problems with name + * pollution (e.g. a global common 'utime' linked to a function). + */ + if (sp && sp->referenced && !sp->defined) + { + int junk; + register int j; + register int offset = symdef_base[i].library_member_offset; + struct file_entry *subentry; + + /* Don't think carefully about any archive member + more than once in a given pass. */ + + if (prev_offset == offset) + continue; + prev_offset = offset; + + /* Read the symbol table of the archive member. */ + + subentry = decode_library_subfile (desc, entry, offset, &junk); + if (subentry == 0) + fatal ("invalid offset for %s in symbol table of %s", + sym_name_base + + symdef_base[i].symbol_name_string_index, + entry->filename); + read_entry_symbols (desc, subentry); + subentry->strings = (char *) malloc (subentry->string_size); + read_entry_strings (desc, subentry); + + /* Now scan the symbol table and decide whether to load. */ + + if (!subfile_wanted_p (subentry)) + { + free (subentry->symbols); + free (subentry); + } + else + { + /* This member is needed; load it. + Since we are loading something on this pass, + we must make another pass through the symdef data. */ + + not_finished = 1; + + enter_file_symbols (subentry); + + if (prev) + prev->chain = subentry; + else entry->subfiles = subentry; + prev = subentry; + + /* Clear out this member's symbols from the symdef data + so that following passes won't waste time on them. */ + + for (j = 0; j < number_of_symdefs; j++) + { + if (symdef_base[j].library_member_offset == offset) + symdef_base[j].symbol_name_string_index = -1; + } + } + + /* We'll read the strings again if we need them again. */ + 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. */ + +void +linear_library (desc, entry) + int desc; + struct file_entry *entry; +{ + register struct file_entry *prev = 0; + register int this_subfile_offset = SARMAG; + + while (undefined_global_sym_count || common_defined_global_count) + { + int member_length; + register struct file_entry *subentry; + + subentry = decode_library_subfile (desc, 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); + + if (!subfile_wanted_p (subentry)) + { + free (subentry->symbols); + free (subentry); + } + else + { + enter_file_symbols (subentry); + + if (prev) + prev->chain = subentry; + else entry->subfiles = subentry; + prev = subentry; + subentry->strings = 0; /* Since space will dissapear on return */ + } + + this_subfile_offset += member_length + sizeof (struct ar_hdr); + if (this_subfile_offset & 1) this_subfile_offset++; + } +} + +/* ENTRY is an entry for a library member. + Its symbols have been read into core, but not entered. + Return nonzero if we ought to load this member. */ + +int +subfile_wanted_p (entry) + struct file_entry *entry; +{ + register struct nlist *p; + register struct nlist *end + = entry->symbols + entry->header.a_syms / sizeof (struct nlist); +#ifdef DOLLAR_KLUDGE + register int dollar_cond = 0; +#endif + + for (p = entry->symbols; p < end; p++) + { + register int type = p->n_type; + register char *name = p->n_un.n_strx + entry->strings; + + /* If the symbol has an interesting definition, we could + potentially want it. */ + if (type & N_EXT + && (type != (N_UNDF | N_EXT) || p->n_value + +#ifdef DOLLAR_KLUDGE + || name[1] == '$' +#endif + ) + && !SET_ELEMENT_P (type) + && !set_element_prefixed_p (name)) + { + register symbol *sp = getsym_soft (name); + +#ifdef DOLLAR_KLUDGE + if (name[1] == '$') + { + sp = getsym_soft (&name[2]); + dollar_cond = 1; + if (!sp) continue; + if (sp->referenced) + { + if (write_map) + { + print_file_name (entry, stdout); + fprintf (stdout, " needed due to $-conditional %s\n", name); + } + return 1; + } + continue; + } +#endif + + /* If this symbol has not been hashed, we can't be looking for it. */ + + if (!sp) continue; + + /* + * We don't load a file if it merely satisfies a common reference + * (see explanation above in symdef_library()). + */ + if (sp->referenced && !sp->defined) + { + /* This is a symbol we are looking for. It is either + not yet defined or defined as a common. */ +#ifdef DOLLAR_KLUDGE + if (dollar_cond) continue; +#endif + if (type == (N_UNDF | N_EXT)) + { + /* Symbol being defined as common. + Remember this, but don't load subfile just for this. */ + + /* If it didn't used to be common, up the count of + common symbols. */ + if (!sp->max_common_size) + common_defined_global_count++; + + if (sp->max_common_size < p->n_value) + sp->max_common_size = p->n_value; + if (!sp->defined) + undefined_global_sym_count--; + sp->defined = 1; + continue; + } + + if (write_map) + { + print_file_name (entry, stdout); + fprintf (stdout, " needed due to %s\n", sp->name); + } + return 1; + } + } + } + + return 0; +} + +void consider_file_section_lengths (), relocate_file_addresses (); + +/* Having entered all the global symbols and found the sizes of sections + of all files to be linked, make all appropriate deductions from this data. + + We propagate global symbol values from definitions to references. + We compute the layout of the output file and where each input file's + contents fit into it. */ + +void +digest_symbols () +{ + register int i; + int setv_fill_count; + + if (trace_files) + fprintf (stderr, "Digesting symbol information:\n\n"); + + /* Compute total size of sections */ + + each_file (consider_file_section_lengths, 0); + + /* If necessary, pad text section to full page in the file. + Include the padding in the text segment size. */ + + if (magic == ZMAGIC) + { + int text_end = text_size + N_TXTOFF (outheader); + text_pad = ((text_end + page_size - 1) & (- page_size)) - text_end; + text_size += text_pad; + } + if (padtext) + { + int text_end = text_size; + text_pad = ((text_end + page_size - 1) & (- page_size)) - text_end; + text_size += text_pad; + } + +#ifdef _N_BASEADDR + /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */ + outheader.a_entry = N_PAGSIZ (outheader); +#endif + + outheader.a_text = text_size; +#ifdef sequent + outheader.a_text += N_ADDRADJ (outheader); +#endif + + /* Make the data segment address start in memory on a suitable boundary. */ + + if (! Tdata_flag_specified) + data_start = N_DATADDR (outheader) + text_start - TEXT_START (outheader); + + /* Set up the set element vector */ + + if (!relocatable_output) + { + /* The set sector size is the number of set elements + a word + for each symbol for the length word at the beginning of the + vector, plus a word for each symbol for a zero at the end of + the vector (for incremental linking). */ + set_sect_size + = (2 * set_symbol_count + set_vector_count) * sizeof (unsigned long); + set_sect_start = data_start + data_size; + data_size += set_sect_size; + set_vectors = (unsigned long *) xmalloc (set_sect_size); + setv_fill_count = 0; + } + + /* Compute start addresses of each file's sections and symbols. */ + + each_full_file (relocate_file_addresses, 0); + + /* Now, for each symbol, verify that it is defined globally at most once. + Put the global value into the symbol entry. + Common symbols are allocated here, in the BSS section. + Each defined symbol is given a '->defined' field + which is the correct N_ code for its definition, + except in the case of common symbols with -r. + Then make all the references point at the symbol entry + instead of being chained together. */ + + defined_global_sym_count = 0; + + for (i = 0; i < TABSIZE; i++) + { + register symbol *sp; + for (sp = symtab[i]; sp; sp = sp->link) + { + /* For each symbol */ + register struct nlist *p, *next; + int defs = 0, com = sp->max_common_size; + struct nlist *first_definition; + for (p = sp->refs; p; p = next) + { + register int type = p->n_type; + + if (SET_ELEMENT_P (type)) + { + if (relocatable_output) + fatal ("internal: global ref to set element with -r"); + if (!defs++) + { + sp->value = set_sect_start + + setv_fill_count++ * sizeof (unsigned long); + sp->defined = N_SETV | N_EXT; + first_definition = p; + } + else if ((sp->defined & ~N_EXT) != N_SETV) + { + sp->multiply_defined = 1; + multiple_def_count++; + } + set_vectors[setv_fill_count++] = p->n_value; + } + else if ((type & N_EXT) && type != (N_UNDF | N_EXT)) + { + /* non-common definition */ + if (defs++ && sp->value != p->n_value) + { + sp->multiply_defined = 1; + multiple_def_count++; + } + sp->value = p->n_value; + sp->defined = type; + first_definition = p; + } + next = (struct nlist *) p->n_un.n_name; + p->n_un.n_name = (char *) sp; + } + /* Allocate as common if defined as common and not defined for real */ + if (com && !defs) + { + if (!relocatable_output || force_common_definition) + { + int align = sizeof (int); + + /* Round up to nearest sizeof (int). I don't know + whether this is necessary or not (given that + alignment is taken care of later), but it's + traditional, so I'll leave it in. Note that if + this size alignment is ever removed, ALIGN above + will have to be initialized to 1 instead of + sizeof (int). */ + + com = (com + sizeof (int) - 1) & (- sizeof (int)); + + while (!(com & align)) + align <<= 1; + + align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align; + + bss_size = ((((bss_size + data_size + data_start) + + (align - 1)) & (- align)) + - data_size - data_start); + + sp->value = data_start + data_size + bss_size; + sp->defined = N_BSS | N_EXT; + bss_size += com; + if (write_map) + printf ("Allocating common %s: %x at %x\n", + sp->name, com, sp->value); + } + else + { + sp->defined = 0; + undefined_global_sym_count++; + } + } + /* Set length word at front of vector and zero byte at end. + Reverse the vector itself to put it in file order. */ + if ((sp->defined & ~N_EXT) == N_SETV) + { + unsigned long length_word_index + = (sp->value - set_sect_start) / sizeof (unsigned long); + unsigned long i, tmp; + + set_vectors[length_word_index] + = setv_fill_count - 1 - length_word_index; + + /* Reverse the vector. */ + for (i = 1; + i < (setv_fill_count - length_word_index - 1) / 2 + 1; + i++) + { + tmp = set_vectors[length_word_index + i]; + set_vectors[length_word_index + i] + = set_vectors[setv_fill_count - i]; + set_vectors[setv_fill_count - i] = tmp; + } + + set_vectors[setv_fill_count++] = 0; + } + if (sp->defined) + defined_global_sym_count++; + } + } + + if (end_symbol) /* These are null if -r. */ + { + etext_symbol->value = text_size + text_start; + edata_symbol->value = data_start + data_size; + end_symbol->value = data_start + data_size + bss_size; + } + + /* Figure the data_pad now, so that it overlaps with the bss addresses. */ + + if (specified_data_size && specified_data_size > data_size) + data_pad = specified_data_size - data_size; + + if (magic == ZMAGIC) + data_pad = ((data_pad + data_size + page_size - 1) & (- page_size)) + - data_size; + + bss_size -= data_pad; + if (bss_size < 0) bss_size = 0; + + data_size += data_pad; +} + +/* Accumulate the section sizes of input file ENTRY + into the section sizes of the output file. */ + +void +consider_file_section_lengths (entry) + register struct file_entry *entry; +{ + if (entry->just_syms_flag) + return; + + entry->text_start_address = text_size; + /* If there were any vectors, we need to chop them off */ + text_size += entry->header.a_text; + entry->data_start_address = data_size; + data_size += entry->header.a_data; + entry->bss_start_address = bss_size; + bss_size += entry->header.a_bss; + + text_reloc_size += entry->header.a_trsize; + data_reloc_size += entry->header.a_drsize; +} + +/* Determine where the sections of ENTRY go into the output file, + whose total section sizes are already known. + Also relocate the addresses of the file's local and debugger symbols. */ + +void +relocate_file_addresses (entry) + register struct file_entry *entry; +{ + entry->text_start_address += text_start; + /* Note that `data_start' and `data_size' have not yet been + adjusted for `data_pad'. If they had been, we would get the wrong + results here. */ + entry->data_start_address += data_start; + entry->bss_start_address += data_start + data_size; + + { + register struct nlist *p; + register struct nlist *end + = entry->symbols + entry->header.a_syms / sizeof (struct nlist); + + for (p = entry->symbols; p < end; p++) + { + /* If this belongs to a section, update it by the section's start address */ + register int type = p->n_type & N_TYPE; + + switch (type) + { + case N_TEXT: + case N_SETT: + p->n_value += entry->text_start_address; + break; + case N_DATA: + case N_SETV: + case N_SETD: + /* A symbol whose value is in the data section + is present in the input file as if the data section + started at an address equal to the length of the file's text. */ + p->n_value += entry->data_start_address - entry->header.a_text; + break; + 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; + break; + } + } + } +} + +void describe_file_sections (), list_file_locals (); + +/* Print a complete or partial map of the output file. */ + +void +print_symbols (outfile) + FILE *outfile; +{ + register int i; + + fprintf (outfile, "\nFiles:\n\n"); + + each_file (describe_file_sections, outfile); + + fprintf (outfile, "\nGlobal symbols:\n\n"); + + for (i = 0; i < TABSIZE; i++) + { + register symbol *sp; + for (sp = symtab[i]; sp; sp = sp->link) + { + if (sp->defined == 1) + fprintf (outfile, " %s: common, length 0x%x\n", sp->name, sp->max_common_size); + if (sp->defined) + fprintf (outfile, " %s: 0x%x\n", sp->name, sp->value); + else if (sp->referenced) + fprintf (outfile, " %s: undefined\n", sp->name); + } + } + + each_file (list_file_locals, outfile); +} + +void +describe_file_sections (entry, outfile) + struct file_entry *entry; + FILE *outfile; +{ + fprintf (outfile, " "); + print_file_name (entry, outfile); + if (entry->just_syms_flag) + fprintf (outfile, " symbols only\n", 0); + else + fprintf (outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n", + entry->text_start_address, entry->header.a_text, + entry->data_start_address, entry->header.a_data, + entry->bss_start_address, entry->header.a_bss); +} + +void +list_file_locals (entry, outfile) + struct file_entry *entry; + FILE *outfile; +{ + register struct nlist + *p, + *end = entry->symbols + entry->header.a_syms / sizeof (struct nlist); + + entry->strings = (char *) alloca (entry->string_size); + read_entry_strings (file_open (entry), entry); + + fprintf (outfile, "\nLocal symbols of "); + print_file_name (entry, outfile); + fprintf (outfile, ":\n\n"); + + for (p = entry->symbols; p < end; p++) + /* If this is a definition, + update it if necessary by this file's start address. */ + if (!(p->n_type & (N_STAB | N_EXT))) + fprintf (outfile, " %s: 0x%x\n", + entry->strings + p->n_un.n_strx, p->n_value); + + entry->strings = 0; /* All done with them. */ +} + + +/* Static vars for do_warnings and subroutines of it */ +int list_unresolved_refs; /* List unresolved refs */ +int list_warning_symbols; /* List warning syms */ +int list_multiple_defs; /* List multiple definitions */ + +/* + * Structure for communication between do_file_warnings and it's + * helper routines. Will in practice be an array of three of these: + * 0) Current line, 1) Next line, 2) Source file info. + */ +struct line_debug_entry +{ + int line; + char *filename; + struct nlist *sym; +}; + +void qsort (); +/* + * Helper routines for do_file_warnings. + */ + +/* Return an integer less than, equal to, or greater than 0 as per the + relation between the two relocation entries. Used by qsort. */ + +int +relocation_entries_relation (rel1, rel2) + struct relocation_info *rel1, *rel2; +{ + return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2); +} + +/* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS + determines the type of the debugging symbol to look for (DSLINE or + SLINE). STATE_POINTER keeps track of the old and new locatiosn in + the file. It assumes that state_pointer[1] is valid; ie + that it.sym points into some entry in the symbol table. If + state_pointer[1].sym == 0, this routine should not be called. */ + +int +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]; +{ + register struct line_debug_entry + *current = state_pointer, + *next = state_pointer + 1, + /* Used to store source file */ + *source = state_pointer + 2; + struct file_entry *entry = (struct file_entry *) source->sym; + + current->sym = next->sym; + current->line = next->line; + current->filename = next->filename; + + while (++(next->sym) < (entry->symbols + + entry->header.a_syms/sizeof (struct nlist))) + { + /* n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80, so + * may look negative...therefore, must mask to low bits + */ + switch (next->sym->n_type & 0xff) + { + case N_SLINE: + if (use_data_symbols) continue; + next->line = next->sym->n_desc; + return 1; + case N_DSLINE: + if (!use_data_symbols) continue; + next->line = next->sym->n_desc; + return 1; +#ifdef HAVE_SUN_STABS + case N_EINCL: + next->filename = source->filename; + continue; +#endif + case N_SO: + source->filename = next->sym->n_un.n_strx + entry->strings; + source->line++; +#ifdef HAVE_SUN_STABS + case N_BINCL: +#endif + case N_SOL: + next->filename + = next->sym->n_un.n_strx + entry->strings; + default: + continue; + } + } + next->sym = (struct nlist *) 0; + return 0; +} + +/* Create a structure to save the state of a scan through the debug + symbols. USE_DATA_SYMBOLS is set if we should be scanning for + DSLINE's instead of SLINE's. entry is the file entry which points + at the symbols to use. */ + +struct line_debug_entry * +init_debug_scan (use_data_symbols, entry) + int use_data_symbols; + struct file_entry *entry; +{ + struct line_debug_entry + *state_pointer + = (struct line_debug_entry *) + xmalloc (3 * sizeof (struct line_debug_entry)); + register struct line_debug_entry + *current = state_pointer, + *next = state_pointer + 1, + *source = state_pointer + 2; /* Used to store source file */ + + struct nlist *tmp; + + for (tmp = entry->symbols; + tmp < (entry->symbols + + entry->header.a_syms/sizeof (struct nlist)); + tmp++) + if (tmp->n_type == (int) N_SO) + break; + + if (tmp >= (entry->symbols + + entry->header.a_syms/sizeof (struct nlist))) + { + /* I believe this translates to "We lose" */ + current->filename = next->filename = entry->filename; + current->line = next->line = -1; + current->sym = next->sym = (struct nlist *) 0; + return state_pointer; + } + + next->line = source->line = 0; + next->filename = source->filename + = (tmp->n_un.n_strx + entry->strings); + source->sym = (struct nlist *) entry; + next->sym = tmp; + + next_debug_entry (use_data_symbols, state_pointer); /* To setup next */ + + if (!next->sym) /* No line numbers for this section; */ + /* setup output results as appropriate */ + { + if (source->line) + { + current->filename = source->filename = entry->filename; + current->line = -1; /* Don't print lineno */ + } + else + { + current->filename = source->filename; + current->line = 0; + } + return state_pointer; + } + + + next_debug_entry (use_data_symbols, state_pointer); /* To setup current */ + + return state_pointer; +} + +/* Takes an ADDRESS (in either text or data space) and a STATE_POINTER + which describes the current location in the implied scan through + the debug symbols within the file which ADDRESS is within, and + returns the source line number which corresponds to ADDRESS. */ + +int +address_to_line (address, state_pointer) + unsigned long address; + /* 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; + + int use_data_symbols; + + if (next->sym) + use_data_symbols = (next->sym->n_type & N_TYPE) == N_DATA; + else + return current->line; + + /* Go back to the beginning if we've already passed it. */ + if (current->sym->n_value > address) + { + tmp_pointer = init_debug_scan (use_data_symbols, + (struct file_entry *) + ((state_pointer + 2)->sym)); + state_pointer[0] = tmp_pointer[0]; + state_pointer[1] = tmp_pointer[1]; + 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->n_value > address) + return -1; + + while (next->sym + && next->sym->n_value <= address + && next_debug_entry (use_data_symbols, state_pointer)) + ; + return current->line; +} + + +/* Macros for manipulating bitvectors. */ +#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7)) +#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7)) + +/* This routine will scan through the relocation data of file ENTRY, + printing out references to undefined symbols and references to + symbols defined in files with N_WARNING symbols. If DATA_SEGMENT + is non-zero, it will scan the data relocation segment (and use + N_DSLINE symbols to track line number); otherwise it will scan the + text relocation segment. Warnings will be printed on the output + stream OUTFILE. Eventually, every nlist symbol mapped through will + be marked in the NLIST_BITVECTOR, so we don't repeat ourselves when + we scan the nlists themselves. */ + +do_relocation_warnings (entry, data_segment, outfile, nlist_bitvector) + struct file_entry *entry; + int data_segment; + FILE *outfile; + unsigned char *nlist_bitvector; +{ + struct relocation_info + *reloc_start = data_segment ? entry->datarel : entry->textrel, + *reloc; + int reloc_size + = ((data_segment ? entry->header.a_drsize : entry->header.a_trsize) + / sizeof (struct relocation_info)); + int start_of_segment + = (data_segment ? entry->data_start_address : entry->text_start_address); + struct nlist *start_of_syms = entry->symbols; + struct line_debug_entry *state_pointer + = init_debug_scan (data_segment != 0, entry); + register struct line_debug_entry + *current = state_pointer; + /* Assigned to generally static values; should not be written into. */ + char *errfmt; + /* Assigned to alloca'd values cand copied into; should be freed + when done. */ + char *errmsg; + int invalidate_line_number; + + /* We need to sort the relocation info here. Sheesh, so much effort + for one lousy error optimization. */ + + qsort (reloc_start, reloc_size, sizeof (struct relocation_info), + relocation_entries_relation); + + for (reloc = reloc_start; + reloc < (reloc_start + reloc_size); + reloc++) + { + register struct nlist *s; + register symbol *g; + + /* If the relocation isn't resolved through a symbol, continue */ + if (!RELOC_EXTERN_P(reloc)) + continue; + + s = &(entry->symbols[RELOC_SYMBOL(reloc)]); + + /* Local symbols shouldn't ever be used by relocation info, so + the next should be safe. + This is, of course, wrong. References to local BSS symbols can be + the targets of relocation info, and they can (must) be + resolved through symbols. However, these must be defined properly, + (the assembler would have caught it otherwise), so we can + ignore these cases. */ + if (!(s->n_type & N_EXT)) + continue; + + g = (symbol *) s->n_un.n_name; + errmsg = 0; + + if (!g->defined && list_unresolved_refs) /* Reference */ + { + /* Mark as being noted by relocation warning pass. */ + SET_BIT (nlist_bitvector, s - start_of_syms); + + if (g->undef_refs >= MAX_UREFS_PRINTED) /* Listed too many */ + continue; + + /* Undefined symbol which we should mention */ + + if (++(g->undef_refs) == MAX_UREFS_PRINTED) + { + errfmt = "More undefined symbol %s refs follow"; + invalidate_line_number = 1; + } + else + { + errfmt = "Undefined symbol %s referenced from %s segment"; + invalidate_line_number = 0; + } + } + else /* Defined */ + { + /* Potential symbol warning here */ + if (!g->warning) continue; + + /* Mark as being noted by relocation warning pass. */ + SET_BIT (nlist_bitvector, s - start_of_syms); + + errfmt = 0; + errmsg = g->warning; + invalidate_line_number = 0; + } + + + /* If errfmt == 0, errmsg has already been defined. */ + if (errfmt != 0) + { + char *nm; + + if (demangler == NULL || (nm = (*demangler)(g->name)) == NULL) + nm = g->name; + errmsg = (char *) xmalloc (strlen (errfmt) + strlen (nm) + 1); + sprintf (errmsg, errfmt, nm, data_segment ? "data" : "text"); + if (nm != g->name) + free (nm); + } + + address_to_line (RELOC_ADDRESS (reloc) + start_of_segment, + state_pointer); + + if (current->line >=0) + fprintf (outfile, "%s:%d: %s\n", current->filename, + invalidate_line_number ? 0 : current->line, errmsg); + else + fprintf (outfile, "%s: %s\n", current->filename, errmsg); + + if (errfmt != 0) + free (errmsg); + } + + free (state_pointer); +} + +/* Print on OUTFILE a list of all warnings generated by references + and/or definitions in the file ENTRY. List source file and line + number if possible, just the .o file if not. */ + +void +do_file_warnings (entry, outfile) + struct file_entry *entry; + FILE *outfile; +{ + int number_of_syms = entry->header.a_syms / sizeof (struct nlist); + unsigned char *nlist_bitvector + = (unsigned char *) alloca ((number_of_syms >> 3) + 1); + struct line_debug_entry *text_scan, *data_scan; + int i; + char *errfmt, *file_name; + int line_number; + int dont_allow_symbol_name; + + bzero (nlist_bitvector, (number_of_syms >> 3) + 1); + + /* Read in the files strings if they aren't available */ + if (!entry->strings) + { + int desc; + + entry->strings = (char *) alloca (entry->string_size); + desc = file_open (entry); + read_entry_strings (desc, entry); + } + + read_file_relocation (entry); + + /* Do text warnings based on a scan through the relocation 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); + + /* 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; + struct glosym *g; + + s = entry->symbols + i; + + if (!(s->n_type & N_EXT)) + continue; + + g = (symbol *) s->n_un.n_name; + dont_allow_symbol_name = 0; + + if (list_multiple_defs && g->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); + file_name = text_scan[0].filename; + break; + case N_DATA | N_EXT: + line_number = address_to_line (s->n_value, data_scan); + file_name = data_scan[0].filename; + break; + case N_SETA | N_EXT: + case N_SETT | N_EXT: + case N_SETD | N_EXT: + case N_SETB | N_EXT: + if (g->multiply_defined == 2) + continue; + errfmt = "First set element definition of symbol %s (multiply defined)"; + break; + default: + continue; /* Don't print out multiple defs + at references. */ + } + } + else if (BIT_SET_P (nlist_bitvector, i)) + continue; + else if (list_unresolved_refs && !g->defined) + { + if (g->undef_refs >= MAX_UREFS_PRINTED) + continue; + + if (++(g->undef_refs) == MAX_UREFS_PRINTED) + errfmt = "More undefined \"%s\" refs follow"; + else + errfmt = "Undefined symbol \"%s\" referenced"; + line_number = -1; + } + else if (g->warning) + { + /* There are two cases in which we don't want to + do this. The first is if this is a definition instead of + 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)) + continue; + + errfmt = g->warning; + line_number = -1; + dont_allow_symbol_name = 1; + } + else + continue; + + if (line_number == -1) + fprintf (outfile, "%s: ", entry->filename); + else + fprintf (outfile, "%s:%d: ", file_name, line_number); + + if (dont_allow_symbol_name) + fprintf (outfile, "%s", errfmt); + else + { + char *nm; + if (demangler != NULL && (nm = (*demangler)(g->name)) != NULL) + { + fprintf (outfile, errfmt, nm); + free (nm); + } + else + fprintf (outfile, errfmt, g->name); + } + + fputc ('\n', outfile); + } + free (text_scan); + free (data_scan); + entry->strings = 0; /* Since it will dissapear anyway. */ +} + +do_warnings (outfile) + FILE *outfile; +{ + list_unresolved_refs = !relocatable_output && undefined_global_sym_count; + list_warning_symbols = warning_count; + list_multiple_defs = multiple_def_count != 0; + + if (!(list_unresolved_refs || + list_warning_symbols || + list_multiple_defs )) + /* No need to run this routine */ + return; + + each_file (do_file_warnings, outfile); + + if (list_unresolved_refs || list_multiple_defs) + make_executable = 0; +} + +/* Write the output file */ + +void +write_output () +{ + struct stat statbuf; + int filemode; + + (void) unlink (output_filename); + outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (outdesc < 0) perror_name (output_filename); + + if (fstat (outdesc, &statbuf) < 0) + perror_name (output_filename); + + (void) fchflags(outdesc, statbuf.st_flags | UF_NODUMP); + + filemode = statbuf.st_mode; + (void) fchmod (outdesc, filemode & ~0111); + + /* Output the a.out header. */ + write_header (); + + /* Output the text and data segments, relocating as we go. */ + write_text (); + write_data (); + + /* Output the merged relocation info, if requested with `-r'. */ + if (relocatable_output) + write_rel (); + + /* Output the symbol table (both globals and locals). */ + write_syms (); + + /* Copy any GDB symbol segments from input files. */ + write_symsegs (); + + if (fchmod (outdesc, filemode | 0111) == -1) + perror_name (output_filename); + + close (outdesc); +} + +void modify_location (), perform_relocation (), copy_text (), copy_data (); + +void +write_header () +{ + N_SET_MAGIC (outheader, magic); + outheader.a_text = text_size; +#ifdef sequent + outheader.a_text += N_ADDRADJ (outheader); + if (entry_symbol == 0) + entry_symbol = getsym("start"); +#endif + outheader.a_data = data_size; + outheader.a_bss = bss_size; + outheader.a_entry = (entry_symbol ? entry_symbol->value + : text_start + entry_offset); +#ifdef COFF_ENCAPSULATE + if (need_coff_header) + { + /* We are encapsulating BSD format within COFF format. */ + struct coffscn *tp, *dp, *bp; + + tp = &coffheader.scns[0]; + dp = &coffheader.scns[1]; + bp = &coffheader.scns[2]; + + strcpy (tp->s_name, ".text"); + tp->s_paddr = text_start; + tp->s_vaddr = text_start; + tp->s_size = text_size; + tp->s_scnptr = sizeof (struct coffheader) + sizeof (struct exec); + tp->s_relptr = 0; + tp->s_lnnoptr = 0; + tp->s_nreloc = 0; + tp->s_nlnno = 0; + tp->s_flags = 0x20; + strcpy (dp->s_name, ".data"); + dp->s_paddr = data_start; + dp->s_vaddr = data_start; + dp->s_size = data_size; + dp->s_scnptr = tp->s_scnptr + tp->s_size; + dp->s_relptr = 0; + dp->s_lnnoptr = 0; + dp->s_nreloc = 0; + dp->s_nlnno = 0; + dp->s_flags = 0x40; + strcpy (bp->s_name, ".bss"); + bp->s_paddr = dp->s_vaddr + dp->s_size; + bp->s_vaddr = bp->s_paddr; + bp->s_size = bss_size; + bp->s_scnptr = 0; + bp->s_relptr = 0; + bp->s_lnnoptr = 0; + bp->s_nreloc = 0; + bp->s_nlnno = 0; + bp->s_flags = 0x80; + + coffheader.f_magic = COFF_MAGIC; + coffheader.f_nscns = 3; + /* store an unlikely time so programs can + * tell that there is a bsd header + */ + coffheader.f_timdat = 1; + coffheader.f_symptr = 0; + coffheader.f_nsyms = 0; + coffheader.f_opthdr = 28; + coffheader.f_flags = 0x103; + /* aouthdr */ + coffheader.magic = ZMAGIC; + coffheader.vstamp = 0; + coffheader.tsize = tp->s_size; + coffheader.dsize = dp->s_size; + coffheader.bsize = bp->s_size; + coffheader.entry = outheader.a_entry; + coffheader.text_start = tp->s_vaddr; + coffheader.data_start = dp->s_vaddr; + } +#endif + +#ifdef INITIALIZE_HEADER + INITIALIZE_HEADER; +#endif + + if (strip_symbols == STRIP_ALL) + nsyms = 0; + else + { + nsyms = (defined_global_sym_count + + undefined_global_sym_count); + if (discard_locals == DISCARD_L) + nsyms += non_L_local_sym_count; + else if (discard_locals == DISCARD_NONE) + nsyms += local_sym_count; + /* One extra for following reference on indirects */ + if (relocatable_output) + nsyms += set_symbol_count + global_indirect_count; + } + + if (strip_symbols == STRIP_NONE) + nsyms += debugger_sym_count; + + outheader.a_syms = nsyms * sizeof (struct nlist); + + if (relocatable_output) + { + outheader.a_trsize = text_reloc_size; + outheader.a_drsize = data_reloc_size; + } + else + { + outheader.a_trsize = 0; + outheader.a_drsize = 0; + } + +#ifdef COFF_ENCAPSULATE + if (need_coff_header) + mywrite (&coffheader, sizeof coffheader, 1, outdesc); +#endif + mywrite (&outheader, sizeof (struct exec), 1, outdesc); + + /* Output whatever padding is required in the executable file + between the header and the start of the text. */ + +#ifndef COFF_ENCAPSULATE + padfile (N_TXTOFF (outheader) - sizeof outheader, outdesc); +#endif +} + +/* Relocate the text segment of each input file + and write to the output file. */ + +void +write_text () +{ + if (trace_files) + fprintf (stderr, "Copying and relocating text:\n\n"); + + each_full_file (copy_text, 0); + file_close (); + + if (trace_files) + fprintf (stderr, "\n"); + + padfile (text_pad, outdesc); +} + +int +text_offset (entry) + struct file_entry *entry; +{ + return entry->starting_offset + N_TXTOFF (entry->header); +} + +/* Read in all of the relocation information */ + +void +read_relocation () +{ + each_full_file (read_file_relocation, 0); +} + +/* Read in the relocation sections of ENTRY if necessary */ + +void +read_file_relocation (entry) + struct file_entry *entry; +{ + register struct relocation_info *reloc; + int desc; + int read_return; + + desc = -1; + if (!entry->textrel) + { + reloc = (struct relocation_info *) xmalloc (entry->header.a_trsize); + desc = file_open (entry); + lseek (desc, + text_offset (entry) + entry->header.a_text + entry->header.a_data, + L_SET); + if (entry->header.a_trsize != (read_return = read (desc, reloc, entry->header.a_trsize))) + { + fprintf (stderr, "Return from read: %d\n", read_return); + fatal_with_file ("premature eof in text relocation of ", entry); + } + entry->textrel = reloc; + } + + if (!entry->datarel) + { + reloc = (struct relocation_info *) xmalloc (entry->header.a_drsize); + if (desc == -1) desc = file_open (entry); + lseek (desc, + text_offset (entry) + entry->header.a_text + + entry->header.a_data + entry->header.a_trsize, + L_SET); + if (entry->header.a_drsize != read (desc, reloc, entry->header.a_drsize)) + fatal_with_file ("premature eof in data relocation of ", entry); + entry->datarel = reloc; + } +} + +/* Read the text segment contents of ENTRY, relocate them, + and write the result to the output file. + If `-r', save the text relocation for later reuse. */ + +void +copy_text (entry) + struct file_entry *entry; +{ + register char *bytes; + register int desc; + register struct relocation_info *reloc; + + if (trace_files) + prline_file_name (entry, stderr); + + desc = file_open (entry); + + /* Allocate space for the file's text section */ + + bytes = (char *) alloca (entry->header.a_text); + + /* Deal with relocation information however is appropriate */ + + if (entry->textrel) reloc = entry->textrel; + else if (relocatable_output) + { + read_file_relocation (entry); + reloc = entry->textrel; + } + else + { + reloc = (struct relocation_info *) alloca (entry->header.a_trsize); + lseek (desc, text_offset (entry) + entry->header.a_text + entry->header.a_data, 0); + if (entry->header.a_trsize != read (desc, reloc, entry->header.a_trsize)) + fatal_with_file ("premature eof in text relocation of ", 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); + + + /* Relocate the text according to the text relocation. */ + + perform_relocation (bytes, entry->text_start_address, entry->header.a_text, + reloc, entry->header.a_trsize, entry); + + /* Write the relocated text to the output file. */ + + mywrite (bytes, 1, entry->header.a_text, outdesc); +} + +/* Relocate the data segment of each input file + and write to the output file. */ + +void +write_data () +{ + if (trace_files) + fprintf (stderr, "Copying and relocating data:\n\n"); + + each_full_file (copy_data, 0); + file_close (); + + /* Write out the set element vectors. See digest symbols for + description of length of the set vector section. */ + + if (set_vector_count) + mywrite (set_vectors, 2 * set_symbol_count + set_vector_count, + sizeof (unsigned long), outdesc); + + if (trace_files) + fprintf (stderr, "\n"); + + padfile (data_pad, outdesc); +} + +/* Read the data segment contents of ENTRY, relocate them, + and write the result to the output file. + If `-r', save the data relocation for later reuse. + See comments in `copy_text'. */ + +void +copy_data (entry) + struct file_entry *entry; +{ + register struct relocation_info *reloc; + register char *bytes; + register int desc; + + if (trace_files) + prline_file_name (entry, stderr); + + desc = file_open (entry); + + bytes = (char *) alloca (entry->header.a_data); + + if (entry->datarel) reloc = entry->datarel; + else if (relocatable_output) /* Will need this again */ + { + read_file_relocation (entry); + reloc = entry->datarel; + } + else + { + reloc = (struct relocation_info *) alloca (entry->header.a_drsize); + lseek (desc, text_offset (entry) + entry->header.a_text + + entry->header.a_data + entry->header.a_trsize, + 0); + if (entry->header.a_drsize != read (desc, reloc, entry->header.a_drsize)) + fatal_with_file ("premature eof in data relocation of ", 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); + + perform_relocation (bytes, entry->data_start_address - entry->header.a_text, + entry->header.a_data, reloc, entry->header.a_drsize, entry); + + mywrite (bytes, 1, entry->header.a_data, outdesc); +} + +/* Relocate ENTRY's text or data section contents. + DATA is the address of the contents, in core. + DATA_SIZE is the length of the contents. + PC_RELOCATION is the difference between the address of the contents + in the output file and its address in the input file. + RELOC_INFO is the address of the relocation info, in core. + RELOC_SIZE is its length in bytes. */ +/* This version is about to be severly hacked by Randy. Hope it + works afterwards. */ +void +perform_relocation (data, pc_relocation, data_size, reloc_info, reloc_size, entry) + char *data; + struct relocation_info *reloc_info; + struct file_entry *entry; + int pc_relocation; + int data_size; + int reloc_size; +{ + register struct relocation_info *p = reloc_info; + struct relocation_info *end + = reloc_info + reloc_size / sizeof (struct relocation_info); + int text_relocation = entry->text_start_address; + int data_relocation = entry->data_start_address - entry->header.a_text; + int bss_relocation + = entry->bss_start_address - entry->header.a_text - entry->header.a_data; + + for (; p < end; p++) + { + register int relocation = 0; + register int addr = RELOC_ADDRESS(p); + register unsigned int mask = 0; + + if (addr >= data_size) + fatal_with_file ("relocation address out of range in ", entry); + + if (RELOC_EXTERN_P(p)) + { + int symindex = RELOC_SYMBOL (p) * sizeof (struct nlist); + symbol *sp = ((symbol *) + (((struct nlist *) + (((char *)entry->symbols) + symindex)) + ->n_un.n_name)); + +#ifdef N_INDR + /* Resolve indirection */ + if ((sp->defined & ~N_EXT) == N_INDR) + sp = (symbol *) sp->value; +#endif + + if (symindex >= entry->header.a_syms) + fatal_with_file ("relocation symbolnum out of range in ", entry); + + /* If the symbol is undefined, leave it at zero. */ + if (! sp->defined) + relocation = 0; + else + relocation = sp->value; + } + else switch (RELOC_TYPE(p)) + { + case N_TEXT: + case N_TEXT | N_EXT: + relocation = text_relocation; + break; + + case N_DATA: + case N_DATA | N_EXT: + /* A word that points to beginning of the the data section + initially contains not 0 but rather the "address" of that section + in the input file, which is the length of the file's text. */ + relocation = data_relocation; + break; + + case N_BSS: + case N_BSS | N_EXT: + /* Similarly, an input word pointing to the beginning of the bss + initially contains the length of text plus data of the file. */ + relocation = bss_relocation; + break; + + case N_ABS: + case N_ABS | N_EXT: + /* Don't know why this code would occur, but apparently it does. */ + break; + + default: + fatal_with_file ("nonexternal relocation code invalid in ", entry); + } + +#ifdef RELOC_ADD_EXTRA + relocation += RELOC_ADD_EXTRA(p); + if (relocatable_output) + { + /* Non-PC relative relocations which are absolute + or which have become non-external now have fixed + relocations. Set the ADD_EXTRA of this relocation + to be the relocation we have now determined. */ + if (! RELOC_PCREL_P (p)) + { + if ((int)p->r_type <= RELOC_32 + || RELOC_EXTERN_P (p) == 0) + RELOC_ADD_EXTRA (p) = relocation; + } + /* External PC-relative relocations continue to move around; + update their relocations by the amount they have moved + so far. */ + else if (RELOC_EXTERN_P (p)) + RELOC_ADD_EXTRA (p) -= pc_relocation; + continue; + } +#endif + + if (RELOC_PCREL_P(p)) + relocation -= pc_relocation; + + relocation >>= RELOC_VALUE_RIGHTSHIFT(p); + + /* Unshifted mask for relocation */ + mask = 1 << RELOC_TARGET_BITSIZE(p) - 1; + mask |= mask - 1; + relocation &= mask; + + /* Shift everything up to where it's going to be used */ + relocation <<= RELOC_TARGET_BITPOS(p); + mask <<= RELOC_TARGET_BITPOS(p); + + switch (RELOC_TARGET_SIZE(p)) + { + case 0: + if (RELOC_MEMORY_SUB_P(p)) + relocation -= mask & *(char *) (data + addr); + else if (RELOC_MEMORY_ADD_P(p)) + relocation += mask & *(char *) (data + addr); + *(char *) (data + addr) &= ~mask; + *(char *) (data + addr) |= relocation; + break; + + case 1: +#ifdef tahoe + if (((int) data + addr & 1) == 0) + { +#endif + if (RELOC_MEMORY_SUB_P(p)) + relocation -= mask & *(short *) (data + addr); + else if (RELOC_MEMORY_ADD_P(p)) + relocation += mask & *(short *) (data + addr); + *(short *) (data + addr) &= ~mask; + *(short *) (data + addr) |= relocation; +#ifdef tahoe + } + /* + * The CCI Power 6 (aka Tahoe) architecture has byte-aligned + * instruction operands but requires data accesses to be aligned. + * Brain-damage... + */ + else + { + unsigned char *da = (unsigned char *) (data + addr); + unsigned short s = da[0] << 8 | da[1]; + + if (RELOC_MEMORY_SUB_P(p)) + relocation -= mask & s; + else if (RELOC_MEMORY_ADD_P(p)) + relocation += mask & s; + s &= ~mask; + s |= relocation; + da[0] = s >> 8; + da[1] = s; + } +#endif + break; + + case 2: +#ifndef _CROSS_TARGET_ARCH +#ifdef tahoe + if (((int) data + addr & 3) == 0) + { +#endif + if (RELOC_MEMORY_SUB_P(p)) + relocation -= mask & *(long *) (data + addr); + else if (RELOC_MEMORY_ADD_P(p)) + relocation += mask & *(long *) (data + addr); + *(long *) (data + addr) &= ~mask; + *(long *) (data + addr) |= relocation; +#ifdef tahoe + } + else + { + unsigned char *da = (unsigned char *) (data + addr); + unsigned long l = da[0] << 24 | da[1] << 16 | da[2] << 8 | da[3]; + + if (RELOC_MEMORY_SUB_P(p)) + relocation -= mask & l; + else if (RELOC_MEMORY_ADD_P(p)) + relocation += mask & l; + l &= ~mask; + l |= relocation; + da[0] = l >> 24; + da[1] = l >> 16; + da[2] = l >> 8; + da[3] = l; + } +#endif +#else + /* Handle long word alignment requirements of SPARC architecture */ + /* WARNING: This fix makes an assumption on byte ordering */ + /* Marc Ullman, Stanford University Nov. 1 1989 */ + if (RELOC_MEMORY_SUB_P(p)) { + relocation -= mask & + ((*(unsigned short *) (data + addr) << 16) | + *(unsigned short *) (data + addr + 2)); + } else if (RELOC_MEMORY_ADD_P(p)) { + relocation += mask & + ((*(unsigned short *) (data + addr) << 16) | + *(unsigned short *) (data + addr + 2)); + } + *(unsigned short *) (data + addr) &= (~mask >> 16); + *(unsigned short *) (data + addr + 2) &= (~mask & 0xffff); + *(unsigned short *) (data + addr) |= (relocation >> 16); + *(unsigned short *) (data + addr + 2) |= (relocation & 0xffff); +#endif + break; + + default: + fatal_with_file ("Unimplemented relocation field length in ", entry); + } + } +} + +/* For relocatable_output only: write out the relocation, + relocating the addresses-to-be-relocated. */ + +void coptxtrel (), copdatrel (); + +void +write_rel () +{ + register int i; + register int count = 0; + + if (trace_files) + 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. */ + + for (i = 0; i < TABSIZE; i++) + { + symbol *sp; + for (sp = symtab[i]; sp; sp = sp->link) + if (sp->referenced || sp->defined) + { + sp->def_count = count++; + /* Leave room for the reference required by N_INDR, if + necessary. */ + if ((sp->defined & ~N_EXT) == N_INDR) + count++; + } + } + /* Correct, because if (relocatable_output), we will also be writing + whatever indirect blocks we have. */ + if (count != defined_global_sym_count + + undefined_global_sym_count + global_indirect_count) + fatal ("internal error"); + + /* Write out the relocations of all files, remembered from copy_text. */ + + each_full_file (coptxtrel, 0); + + if (trace_files) + fprintf (stderr, "\nWriting data relocation:\n\n"); + + each_full_file (copdatrel, 0); + + if (trace_files) + fprintf (stderr, "\n"); +} + +void +coptxtrel (entry) + struct file_entry *entry; +{ + register struct relocation_info *p, *end; + register int reloc = entry->text_start_address; + + p = entry->textrel; + end = (struct relocation_info *) (entry->header.a_trsize + (char *) p); + while (p < end) + { + RELOC_ADDRESS(p) += reloc; + if (RELOC_EXTERN_P(p)) + { + register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist); + symbol *symptr = ((symbol *) + (((struct nlist *) + (((char *)entry->symbols) + symindex)) + ->n_un.n_name)); + + if (symindex >= entry->header.a_syms) + fatal_with_file ("relocation symbolnum out of range in ", entry); + +#ifdef N_INDR + /* Resolve indirection. */ + if ((symptr->defined & ~N_EXT) == N_INDR) + symptr = (symbol *) symptr->value; +#endif + + /* If the symbol is now defined, change the external relocation + to an internal one. */ + + if (symptr->defined) + { + RELOC_EXTERN_P(p) = 0; + RELOC_SYMBOL(p) = (symptr->defined & N_TYPE); +#ifdef RELOC_ADD_EXTRA + /* If we aren't going to be adding in the value in + memory on the next pass of the loader, then we need + to add it in from the relocation entry. Otherwise + the work we did in this pass is lost. */ + if (!RELOC_MEMORY_ADD_P(p)) + RELOC_ADD_EXTRA (p) += symptr->value; +#endif + } + else + /* Debugger symbols come first, so have to start this + after them. */ + RELOC_SYMBOL(p) = (symptr->def_count + nsyms + - defined_global_sym_count + - undefined_global_sym_count + - global_indirect_count); + } + p++; + } + mywrite (entry->textrel, 1, entry->header.a_trsize, outdesc); +} + +void +copdatrel (entry) + struct file_entry *entry; +{ + register struct relocation_info *p, *end; + /* Relocate the address of the relocation. + Old address is relative to start of the input file's data section. + New address is relative to start of the output file's data section. */ + register int reloc = entry->data_start_address - text_size; + + p = entry->datarel; + end = (struct relocation_info *) (entry->header.a_drsize + (char *) p); + while (p < end) + { + RELOC_ADDRESS(p) += reloc; + if (RELOC_EXTERN_P(p)) + { + register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist); + symbol *symptr = ((symbol *) + (((struct nlist *) + (((char *)entry->symbols) + symindex)) + ->n_un.n_name)); + int symtype; + + if (symindex >= entry->header.a_syms) + fatal_with_file ("relocation symbolnum out of range in ", entry); + +#ifdef N_INDR + /* Resolve indirection. */ + if ((symptr->defined & ~N_EXT) == N_INDR) + symptr = (symbol *) symptr->value; +#endif + + symtype = symptr->defined & N_TYPE; + + if (force_common_definition + || symtype == N_DATA || symtype == N_TEXT || symtype == N_ABS) + { + RELOC_EXTERN_P(p) = 0; + RELOC_SYMBOL(p) = symtype; + } + else + /* Debugger symbols come first, so have to start this + after them. */ + RELOC_SYMBOL(p) + = (((symbol *) + (((struct nlist *) + (((char *)entry->symbols) + symindex)) + ->n_un.n_name)) + ->def_count + + nsyms - defined_global_sym_count + - undefined_global_sym_count + - global_indirect_count); + } + p++; + } + mywrite (entry->datarel, 1, entry->header.a_drsize, outdesc); +} + +void write_file_syms (); +void write_string_table (); + +/* Offsets and current lengths of symbol and string tables in output file. */ + +int symbol_table_offset; +int symbol_table_len; + +/* Address in output file where string table starts. */ +int string_table_offset; + +/* Offset within string table + where the strings in `strtab_vector' should be written. */ +int string_table_len; + +/* Total size of string table strings allocated so far, + including strings in `strtab_vector'. */ +int strtab_size; + +/* Vector whose elements are strings to be added to the string table. */ +char **strtab_vector; + +/* Vector whose elements are the lengths of those strings. */ +int *strtab_lens; + +/* Index in `strtab_vector' at which the next string will be stored. */ +int strtab_index; + +/* Add the string NAME to the output file string table. + Record it in `strtab_vector' to be output later. + Return the index within the string table that this string will have. */ + +int +assign_string_table_index (name) + char *name; +{ + register int index = strtab_size; + register int len = strlen (name) + 1; + + strtab_size += len; + strtab_vector[strtab_index] = name; + strtab_lens[strtab_index++] = len; + + return index; +} + +FILE *outstream = (FILE *) 0; + +/* Write the contents of `strtab_vector' into the string table. + This is done once for each file's local&debugger symbols + and once for the global symbols. */ + +void +write_string_table () +{ + register int i; + + lseek (outdesc, string_table_offset + string_table_len, 0); + + if (!outstream) + 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); + + /* Report I/O error such as disk full. */ + if (ferror (outstream)) + perror_name (output_filename); +} + +/* Write the symbol table and string table of the output file. */ + +void +write_syms () +{ + /* Number of symbols written so far. */ + int syms_written = 0; + register int i; + register symbol *sp; + + /* Buffer big enough for all the global symbols. One + extra struct for each indirect symbol to hold the extra reference + following. */ + struct nlist *buf + = (struct nlist *) alloca ((defined_global_sym_count + + undefined_global_sym_count + + global_indirect_count) + * sizeof (struct nlist)); + /* Pointer for storing into BUF. */ + register struct nlist *bufp = buf; + + /* Size of string table includes the bytes that store the size. */ + strtab_size = sizeof strtab_size; + + symbol_table_offset = N_SYMOFF (outheader); + symbol_table_len = 0; + string_table_offset = N_STROFF (outheader); + string_table_len = strtab_size; + + if (strip_symbols == STRIP_ALL) + return; + + /* Write the local symbols defined by the various files. */ + + each_file (write_file_syms, &syms_written); + file_close (); + + /* Now write out the global symbols. */ + + /* Allocate two vectors that record the data to generate the string + table from the global symbols written so far. This must include + extra space for the references following indirect outputs. */ + + strtab_vector = (char **) alloca ((num_hash_tab_syms + + global_indirect_count) * sizeof (char *)); + strtab_lens = (int *) alloca ((num_hash_tab_syms + + global_indirect_count) * sizeof (int)); + strtab_index = 0; + + /* Scan the symbol hash table, bucket by bucket. */ + + for (i = 0; i < TABSIZE; i++) + for (sp = symtab[i]; sp; sp = sp->link) + { + struct nlist nl; + + nl.n_other = 0; + nl.n_desc = 0; + + /* Compute a `struct nlist' for the symbol. */ + + if (sp->defined || sp->referenced) + { + /* common condition needs to be before undefined condition */ + /* because unallocated commons are set undefined in */ + /* digest_symbols */ + if (sp->defined > 1) /* defined with known type */ + { + /* If the target of an indirect symbol has been + defined and we are outputting an executable, + resolve the indirection; it's no longer needed */ + if (!relocatable_output + && ((sp->defined & N_TYPE) == N_INDR) + && (((symbol *) sp->value)->defined > 1)) + { + symbol *newsp = (symbol *) sp->value; + nl.n_type = newsp->defined; + nl.n_value = newsp->value; + } + else + { + nl.n_type = sp->defined; + if (sp->defined != (N_INDR | N_EXT)) + nl.n_value = sp->value; + else + nl.n_value = 0; + } + } + else if (sp->max_common_size) /* defined as common but not allocated. */ + { + /* happens only with -r and not -d */ + /* write out a common definition */ + nl.n_type = N_UNDF | N_EXT; + nl.n_value = sp->max_common_size; + } + else if (!sp->defined) /* undefined -- legit only if -r */ + { + nl.n_type = N_UNDF | N_EXT; + nl.n_value = 0; + } + else + fatal ("internal error: %s defined in mysterious way", sp->name); + + /* Allocate string table space for the symbol name. */ + + nl.n_un.n_strx = assign_string_table_index (sp->name); + + /* Output to the buffer and count it. */ + + *bufp++ = nl; + syms_written++; + if (nl.n_type == (N_INDR | N_EXT)) + { + struct nlist xtra_ref; + xtra_ref.n_type = N_EXT | N_UNDF; + xtra_ref.n_un.n_strx + = assign_string_table_index (((symbol *) sp->value)->name); + xtra_ref.n_other = 0; + xtra_ref.n_desc = 0; + xtra_ref.n_value = 0; + *bufp++ = xtra_ref; + syms_written++; + } + } + } + + /* Output the buffer full of `struct nlist's. */ + + lseek (outdesc, symbol_table_offset + symbol_table_len, 0); + mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc); + symbol_table_len += sizeof (struct nlist) * (bufp - buf); + + if (syms_written != nsyms) + fatal ("internal error: wrong number of symbols written into output file", 0); + + if (symbol_table_offset + symbol_table_len != string_table_offset) + fatal ("internal error: inconsistent symbol table length", 0); + + /* Now the total string table size is known, so write it. + We are already positioned at the right place in the file. */ + + mywrite (&strtab_size, sizeof (int), 1, outdesc); /* we're at right place */ + + /* Write the strings for the global symbols. */ + + write_string_table (); +} + +/* Write the local and debugger symbols of file ENTRY. + Increment *SYMS_WRITTEN_ADDR for each symbol that is written. */ + +/* Note that we do not combine identical names of local symbols. + dbx or gdb would be confused if we did that. */ + +void +write_file_syms (entry, syms_written_addr) + struct file_entry *entry; + int *syms_written_addr; +{ + register struct nlist *p = entry->symbols; + register struct nlist *end = p + entry->header.a_syms / sizeof (struct nlist); + + /* Buffer to accumulate all the syms before writing them. + It has one extra slot for the local symbol we generate here. */ + struct nlist *buf + = (struct nlist *) alloca (entry->header.a_syms + sizeof (struct nlist)); + register struct nlist *bufp = buf; + + /* Upper bound on number of syms to be written here. */ + int max_syms = (entry->header.a_syms / sizeof (struct nlist)) + 1; + + /* Make tables that record, for each symbol, its name and its name's 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_index = 0; + + /* Generate a local symbol for the start of this file's text. */ + + if (discard_locals != DISCARD_ALL) + { + 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_value = entry->text_start_address; + nl.n_desc = 0; + nl.n_other = 0; + *bufp++ = nl; + (*syms_written_addr)++; + entry->local_syms_offset = *syms_written_addr * sizeof (struct nlist); + } + + /* Read the file's string table. */ + + entry->strings = (char *) alloca (entry->string_size); + read_entry_strings (file_open (entry), entry); + + for (; p < end; p++) + { + register int type = p->n_type; + register int write = 0; + + /* WRITE gets 1 for a non-global symbol that should be written. */ + + + if (SET_ELEMENT_P (type)) /* This occurs even if global. These */ + /* types of symbols are never written */ + /* globally, though they are stored */ + /* globally. */ + write = relocatable_output; + else if (!(type & (N_STAB | N_EXT))) + /* ordinary local symbol */ + write = ((discard_locals != DISCARD_ALL) + && !(discard_locals == DISCARD_L && + (p->n_un.n_strx + entry->strings)[0] == LPREFIX) + && type != N_WARNING); + else if (!(type & N_EXT)) + /* debugger symbol */ + write = (strip_symbols == STRIP_NONE); + + if (write) + { + /* If this symbol has a name, + allocate space for it in the output string table. */ + + if (p->n_un.n_strx) + p->n_un.n_strx = assign_string_table_index (p->n_un.n_strx + + entry->strings); + + /* Output this symbol to the buffer and count it. */ + + *bufp++ = *p; + (*syms_written_addr)++; + } + } + + /* All the symbols are now in BUF; write them. */ + + lseek (outdesc, symbol_table_offset + symbol_table_len, 0); + mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc); + symbol_table_len += sizeof (struct nlist) * (bufp - buf); + + /* Write the string-table data for the symbols just written, + using the data in vectors `strtab_vector' and `strtab_lens'. */ + + write_string_table (); + entry->strings = 0; /* Since it will dissapear anyway. */ +} + +/* Copy any GDB symbol segments from the input files to the output file. + The contents of the symbol segment is copied without change + except that we store some information into the beginning of it. */ + +void write_file_symseg (); + +void +write_symsegs () +{ + each_file (write_file_symseg, 0); +} + +void +write_file_symseg (entry) + struct file_entry *entry; +{ + char buffer[4096]; + struct symbol_root root; + int indesc; + int len; + + if (entry->symseg_offset == 0) + return; + + /* This entry has a symbol segment. Read the root of the segment. */ + + indesc = file_open (entry); + lseek (indesc, entry->symseg_offset + entry->starting_offset, 0); + if (sizeof root != read (indesc, &root, sizeof root)) + fatal_with_file ("premature end of file in symbol segment of ", entry); + + /* Store some relocation info into the root. */ + + root.ldsymoff = entry->local_syms_offset; + root.textrel = entry->text_start_address; + root.datarel = entry->data_start_address - entry->header.a_text; + root.bssrel = entry->bss_start_address + - entry->header.a_text - entry->header.a_data; + root.databeg = entry->data_start_address - root.datarel; + root.bssbeg = entry->bss_start_address - root.bssrel; + + /* Write the modified root into the output file. */ + + mywrite (&root, sizeof root, 1, outdesc); + + /* Copy the rest of the symbol segment unchanged. */ + + if (entry->superfile) + { + /* Library member: number of bytes to copy is determined + from the member's total size. */ + + int total = entry->total_size - entry->symseg_offset - sizeof root; + + while (total > 0) + { + len = read (indesc, buffer, min (sizeof buffer, total)); + + if (len != min (sizeof buffer, total)) + fatal_with_file ("premature end of file in symbol segment of ", entry); + total -= len; + mywrite (buffer, len, 1, outdesc); + } + } + else + { + /* A separate file: copy until end of file. */ + + while (len = read (indesc, buffer, sizeof buffer)) + { + mywrite (buffer, len, 1, outdesc); + if (len < sizeof buffer) + break; + } + } + + file_close (); +} + +/* Create the symbol table entries for `etext', `edata' and `end'. */ + +void +symtab_init () +{ +#ifndef nounderscore + edata_symbol = getsym ("_edata"); + etext_symbol = getsym ("_etext"); + end_symbol = getsym ("_end"); +#else + edata_symbol = getsym ("edata"); + etext_symbol = getsym ("etext"); + end_symbol = getsym ("end"); +#endif + +#ifdef sun + { + symbol *dynamic_symbol = getsym ("__DYNAMIC"); + dynamic_symbol->defined = N_ABS | N_EXT; + dynamic_symbol->referenced = 1; + dynamic_symbol->value = 0; + } +#endif + +#ifdef sequent + { + symbol *_387_flt_symbol = getsym ("_387_flt"); + _387_flt_symbol->defined = N_ABS | N_EXT; + _387_flt_symbol->referenced = 1; + _387_flt_symbol->value = 0; + } +#endif + + edata_symbol->defined = N_DATA | N_EXT; + etext_symbol->defined = N_TEXT | N_EXT; + end_symbol->defined = N_BSS | N_EXT; + + edata_symbol->referenced = 1; + etext_symbol->referenced = 1; + end_symbol->referenced = 1; +} + +/* Compute the hash code for symbol name KEY. */ + +int +hash_string (key) + char *key; +{ + register char *cp; + register int k; + + cp = key; + k = 0; + while (*cp) + k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; + + return k; +} + +/* Get the symbol table entry for the global symbol named KEY. + Create one if there is none. */ + +symbol * +getsym (key) + char *key; +{ + register int hashval; + register symbol *bp; + + /* Determine the proper bucket. */ + + hashval = hash_string (key) % TABSIZE; + + /* Search the bucket. */ + + for (bp = symtab[hashval]; bp; bp = bp->link) + if (! strcmp (key, bp->name)) + return bp; + + /* Nothing was found; create a new symbol table entry. */ + + bp = (symbol *) xmalloc (sizeof (symbol)); + bp->refs = 0; + bp->name = (char *) xmalloc (strlen (key) + 1); + strcpy (bp->name, key); + bp->defined = 0; + bp->referenced = 0; + bp->trace = 0; + bp->value = 0; + bp->max_common_size = 0; + bp->warning = 0; + bp->undef_refs = 0; + bp->multiply_defined = 0; + + /* Add the entry to the bucket. */ + + bp->link = symtab[hashval]; + symtab[hashval] = bp; + + ++num_hash_tab_syms; + + return bp; +} + +/* Like `getsym' but return 0 if the symbol is not already known. */ + +symbol * +getsym_soft (key) + char *key; +{ + register int hashval; + register symbol *bp; + + /* Determine which bucket. */ + + hashval = hash_string (key) % TABSIZE; + + /* Search the bucket. */ + + for (bp = symtab[hashval]; bp; bp = bp->link) + if (! strcmp (key, bp->name)) + return bp; + + return 0; +} + +/* Report a fatal error. + STRING is a printf format string and ARG is one arg for it. */ + +void +fatal (string, arg) + char *string, *arg; +{ + fprintf (stderr, "ld: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Report a fatal error. The error message is STRING + followed by the filename of ENTRY. */ + +void +fatal_with_file (string, entry) + char *string; + struct file_entry *entry; +{ + fprintf (stderr, "ld: "); + fprintf (stderr, string); + print_file_name (entry, stderr); + fprintf (stderr, "\n"); + 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; +{ + extern int errno; + 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; +{ + extern int errno; + char *s; + + if (errno < sys_nerr) + s = concat ("", sys_errlist[errno], " for "); + else + s = "cannot open "; + fatal_with_file (s, entry); +} + +/* Report a nonfatal error. + STRING is a format for printf, and ARG1 ... ARG3 are args for it. */ + +void +error (string, arg1, arg2, arg3) + char *string, *arg1, *arg2, *arg3; +{ + fprintf (stderr, "%s: ", progname); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); +} + + +/* Output COUNT*ELTSIZE bytes of data at BUF + to the descriptor DESC. */ + +void +mywrite (buf, count, eltsize, desc) + char *buf; + int count; + int eltsize; + int desc; +{ + register int val; + register int bytes = count * eltsize; + + while (bytes > 0) + { + val = write (desc, buf, bytes); + if (val <= 0) + perror_name (output_filename); + buf += val; + bytes -= val; + } +} + +/* Output PADDING zero-bytes to descriptor OUTDESC. + PADDING may be negative; in that case, do nothing. */ + +void +padfile (padding, outdesc) + int padding; + int outdesc; +{ + register char *buf; + if (padding <= 0) + return; + + buf = (char *) alloca (padding); + bzero (buf, padding); + mywrite (buf, padding, 1, outdesc); +} + +/* Return a newly-allocated string + whose contents concatenate the strings S1, S2, S3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + register int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + register 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; +} + +/* 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; +{ + int x; + if (1 != sscanf (arg, format, &x)) + fatal (error, arg); + return x; +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +int +xmalloc (size) + int size; +{ + register int result = malloc (size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +/* Like realloc but get fatal error if memory is exhausted. */ + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + register int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +#ifdef USG + +void +bzero (p, n) + char *p; +{ + memset (p, 0, n); +} + +void +bcopy (from, to, n) + char *from, *to; +{ + memcpy (to, from, n); +} + +getpagesize () +{ + return (4096); +} + +#endif + +#if defined(sun) && (TARGET == SUN4) + +/* Don't use local pagesize to build for Sparc. */ + +getpagesize () +{ + return (8192); +} +#endif diff --git a/usr.bin/ld/symseg.h b/usr.bin/ld/symseg.h new file mode 100644 index 0000000..978d8be --- /dev/null +++ b/usr.bin/ld/symseg.h @@ -0,0 +1,358 @@ +/*- + * + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * @(#)symseg.h 8.1 (Berkeley) 6/6/93 + */ + +/* GDB symbol table format definitions. + Copyright (C) 1987, 1988 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 1, 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. */ + +/* Format of GDB symbol table data. + There is one symbol segment for each source file or + independant compilation. These segments are simply concatenated + to form the GDB symbol table. A zero word where the beginning + of a segment is expected indicates there are no more segments. + +Format of a symbol segment: + + The symbol segment begins with a word containing 1 + if it is in the format described here. Other formats may + be designed, with other code numbers. + + The segment contains many objects which point at each other. + The pointers are offsets in bytes from the beginning of the segment. + Thus, each segment can be loaded into core and its pointers relocated + to make valid in-core pointers. + + All the data objects in the segment can be found indirectly from + one of them, the root object, of type `struct symbol_root'. + It appears at the beginning of the segment. + + The total size of the segment, in bytes, appears as the `length' + field of this object. This size includes the size of the + root object. + + All the object data types are defined here to contain pointer types + appropriate for in-core use on a relocated symbol segment. + Casts to and from type int are required for working with + unrelocated symbol segments such as are found in the file. + + The ldsymaddr word is filled in by the loader to contain + the offset (in bytes) within the ld symbol table + of the first nonglobal symbol from this compilation. + This makes it possible to match those symbols + (which contain line number information) reliably with + the segment they go with. + + Core addresses within the program that appear in the symbol segment + are not relocated by the loader. They are inserted by the assembler + and apply to addresses as output by the assembler, so GDB must + relocate them when it loads the symbol segment. It gets the information + on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg + words of the root object. + + The words textrel, datarel and bssrel + are filled in by ld with the amounts to relocate within-the-file + text, data and bss addresses by; databeg and bssbeg can be + used to tell which kind of relocation an address needs. */ + +enum language {language_c}; + +struct symbol_root +{ + int format; /* Data format version */ + int length; /* # bytes in this symbol segment */ + int ldsymoff; /* Offset in ld symtab of this file's syms */ + int textrel; /* Relocation for text addresses */ + int datarel; /* Relocation for data addresses */ + int bssrel; /* Relocation for bss addresses */ + char *filename; /* Name of main source file compiled */ + char *filedir; /* Name of directory it was reached from */ + struct blockvector *blockvector; /* Vector of all symbol-naming blocks */ + struct typevector *typevector; /* Vector of all data types */ + enum language language; /* Code identifying the language used */ + char *version; /* Version info. Not fully specified */ + char *compilation; /* Compilation info. Not fully specified */ + int databeg; /* Address within the file of data start */ + int bssbeg; /* Address within the file of bss start */ + struct sourcevector *sourcevector; /* Vector of line-number info */ +}; + +/* All data types of symbols in the compiled program + are represented by `struct type' objects. + All of these objects are pointed to by the typevector. + The type vector may have empty slots that contain zero. */ + +struct typevector +{ + int length; /* Number of types described */ + struct type *type[1]; +}; + +/* 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, lower bound zero */ + 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 */ + TYPE_CODE_FLT, /* Floating type */ + TYPE_CODE_VOID, /* Void type (values zero length) */ + TYPE_CODE_SET, /* Pascal sets */ + TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ + TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */ +}; + +/* This appears in a type's flags word for an unsigned integer type. */ +#define TYPE_FLAG_UNSIGNED 1 + +/* Other flag bits are used with GDB. */ + +struct type +{ + /* Code for kind of type */ + enum type_code code; + /* Name of this type, or zero if none. + This is used for printing only. + Type names specified as input are defined by symbols. */ + char *name; + /* Length in bytes of storage for a value of this type */ + int length; + /* For a pointer type, describes the type of object pointed to. + For an array type, describes the type of the elements. + For a function type, describes the type of the value. + Unused otherwise. */ + struct type *target_type; + /* Type that is a pointer to this type. + Zero 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; + /* Type that is a function returning this type. + Zero 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 range types, there are two "fields", that record constant values + (inclusive) for the minimum and maximum. + + 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. */ + 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. */ + int 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. + Zero for range bounds and array domains. */ + char *name; + } *fields; +}; + +/* 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 first two blocks in the blockvector are special. + The first one contains all the symbols defined in this compilation + whose scope is the entire program linked together. + The second one contains all the symbols whose scope is the + entire compilation excluding other separate compilations. + In C, these correspond to global symbols and static symbols. + + Each block records a range of core addresses for the code that + is in the scope of the block. The first two special blocks + 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]; +}; + +struct block +{ + /* Addresses in the executable code that are in this block. + Note: in an unrelocated symbol segment in a file, + these are always zero. They can be filled in from the + N_LBRAC and N_RBRAC symbols in the loader symbol table. */ + int startaddr, endaddr; + /* The symbol that names this block, + if the block is the body of a function; + otherwise, zero. + Note: In an unrelocated symbol segment in an object file, + this field may be zero even when the block has a name. + That is because the block is output before the name + (since the name resides in a higher block). + Since the symbol does point to the block (as its value), + it is possible to find the block and set its name properly. */ + struct symbol *function; + /* The `struct block' for the containing block, or 0 if none. */ + /* Note that in an unrelocated symbol segment in an object file + this pointer may be zero when the correct value should be + the second special block (for symbols whose scope is one compilation). + This is because the compiler ouptuts the special blocks at the + very end, after the other blocks. */ + struct block *superblock; + /* Number of local symbols. */ + int nsyms; + /* The symbols. */ + struct symbol *sym[1]; +}; + +/* 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. + + VAR_NAMESPACE is the usual namespace. + In C, this contains variables, function names, typedef names + and enum type values. + + 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. + + LABEL_NAMESPACE may be used for names of labels (for gotos); + currently it is not used and labels are not recorded at all. */ + +/* For a non-global symbol allocated statically, + the correct core address cannot be determined by the compiler. + The compiler puts an index number into the symbol's value field. + This index number can be matched with the "desc" field of + an entry in the loader symbol table. */ + +enum namespace +{ + UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE, +}; + +/* An address-class says where to find the value of the symbol in core. */ + +enum address_class +{ + LOC_UNDEF, /* Not used; catches errors */ + LOC_CONST, /* Value is constant int */ + LOC_STATIC, /* Value is at fixed address */ + LOC_REGISTER, /* Value is in register */ + LOC_ARG, /* Value is at spec'd position in arglist */ + LOC_LOCAL, /* Value is at spec'd pos in stack frame */ + LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE + Symbols in the namespace STRUCT_NAMESPACE + all have this class. */ + LOC_LABEL, /* Value is address in the code */ + LOC_BLOCK, /* Value is address of a `struct block'. + Function names have this class. */ + LOC_EXTERNAL, /* Value is at address not in this compilation. + This is used for .comm symbols + and for extern symbols within functions. + Inside GDB, this is changed to LOC_STATIC once the + real address is obtained from a loader symbol. */ + LOC_CONST_BYTES /* Value is a constant byte-sequence. */ +}; + +struct symbol +{ + /* Symbol name */ + char *name; + /* Name space code. */ + enum namespace namespace; + /* Address class */ + enum address_class class; + /* Data type of value */ + struct type *type; + /* constant value, or address if static, or register number, + or offset in arguments, or offset in stack frame. */ + union + { + long value; + struct block *block; /* for LOC_BLOCK */ + char *bytes; /* for LOC_CONST_BYTES */ + } + value; +}; + +/* Source-file information. + This describes the relation between source files and line numbers + and addresses in the program text. */ + +struct sourcevector +{ + int length; /* Number of source files described */ + struct source *source[1]; /* Descriptions of the files */ +}; + +/* Line number and address of one line. */ + +struct line +{ + int linenum; + int address; +}; + +/* All the information on one source file. */ + +struct source +{ + char *name; /* Name of file */ + int nlines; /* Number of lines that follow */ + struct line lines[1]; /* Information on each line */ +}; diff --git a/usr.bin/leave/Makefile b/usr.bin/leave/Makefile new file mode 100644 index 0000000..87a6ac3 --- /dev/null +++ b/usr.bin/leave/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= leave + +.include diff --git a/usr.bin/leave/leave.1 b/usr.bin/leave/leave.1 new file mode 100644 index 0000000..68c8b4b --- /dev/null +++ b/usr.bin/leave/leave.1 @@ -0,0 +1,102 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)leave.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt LEAVE 1 +.Os +.Sh NAME +.Nm leave +.Nd remind you when you have to leave +.Sh SYNOPSIS +.Nm leave +.Sm off +.Oo +.Op Cm \&+ +.Ns Ar hhmm +.Oc +.Sm on +.Sh DESCRIPTION +.Nm Leave +waits until the specified time, then reminds you that you +have to leave. +You are reminded 5 minutes and 1 minute before the actual +time, at the time, and every minute thereafter. +When you log off, +.Nm leave +exits just before it would have +printed the next message. +.Pp +Options: +.Pp +.Bl -tag -width flag +.It Ar hhmm +The time of day is in the form +.Ar hhmm +where +.Ar hh +is a time in +hours (on a 12 or 24 hour clock), and +.Ar mm +are minutes. +All times are converted to a 12 hour clock, and assumed to +be in the next 12 hours. +.It Cm \&+ +If the time is preceded by +.Ql Cm \&+ , +the alarm will go off in hours and minutes +from the current time. +.El +.Pp +If no argument is given, +.Nm leave +prompts with "When do you +have to leave?". A reply of newline causes +.Nm leave +to exit, +otherwise the reply is assumed to be a time. +This form is suitable for inclusion in a +.Pa .login +or +.Pa .profile. +.Pp +Leave ignores interrupts, quits, and terminates. +To get rid of it you should either log off or use +.Ql kill \-9 +giving its process id. +.Sh SEE ALSO +.Xr calendar 1 +.Sh HISTORY +The +.Nm leave +command appeared in +.Bx 3.0 . diff --git a/usr.bin/leave/leave.c b/usr.bin/leave/leave.c new file mode 100644 index 0000000..56d9d19 --- /dev/null +++ b/usr.bin/leave/leave.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1980, 1988, 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 copyright[] = +"@(#) Copyright (c) 1980, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)leave.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +/* + * leave [[+]hhmm] + * + * Reminds you when you have to leave. + * Leave prompts for input and goes away if you hit return. + * It nags you like a mother hen. + */ +main(argc, argv) + int argc; + char **argv; +{ + register u_int secs; + register int hours, minutes; + register char c, *cp; + struct tm *t, *localtime(); + time_t now, time(); + int plusnow; + char buf[50]; + + if (argc < 2) { +#define MSG1 "When do you have to leave? " + (void)write(1, MSG1, sizeof(MSG1) - 1); + cp = fgets(buf, sizeof(buf), stdin); + if (*cp == '\n') + exit(0); + } else + cp = argv[1]; + + if (*cp == '+') { + plusnow = 1; + ++cp; + } else { + plusnow = 0; + (void)time(&now); + t = localtime(&now); + } + + for (hours = 0; (c = *cp) && c != '\n'; ++cp) { + if (!isdigit(c)) + usage(); + hours = hours * 10 + (c - '0'); + } + minutes = hours % 100; + hours /= 100; + + if (minutes < 0 || minutes > 59) + usage(); + if (plusnow) + secs = hours * 60 * 60 + minutes * 60; + else { + if (hours > 23 || t->tm_hour > hours || + t->tm_hour == hours && minutes <= t->tm_min) + usage(); + secs = (hours - t->tm_hour) * 60 * 60; + secs += (minutes - t->tm_min) * 60; + } + doalarm(secs); + exit(0); +} + +doalarm(secs) + u_int secs; +{ + register int bother; + time_t daytime, time(); + int pid; + char *ctime(); + + if (pid = fork()) { + (void)time(&daytime); + daytime += secs; + printf("Alarm set for %.16s. (pid %d)\n", + ctime(&daytime), pid); + exit(0); + } + sleep((u_int)2); /* let parent print set message */ + + /* + * if write fails, we've lost the terminal through someone else + * causing a vhangup by logging in. + */ +#define FIVEMIN (5 * 60) +#define MSG2 "\07\07You have to leave in 5 minutes.\n" + if (secs >= FIVEMIN) { + sleep(secs - FIVEMIN); + if (write(1, MSG2, sizeof(MSG2) - 1) != sizeof(MSG2) - 1) + exit(0); + secs = FIVEMIN; + } + +#define ONEMIN (60) +#define MSG3 "\07\07Just one more minute!\n" + if (secs >= ONEMIN) { + sleep(secs - ONEMIN); + if (write(1, MSG3, sizeof(MSG3) - 1) != sizeof(MSG3) - 1) + exit(0); + } + +#define MSG4 "\07\07Time to leave!\n" + for (bother = 10; bother--;) { + sleep((u_int)ONEMIN); + if (write(1, MSG4, sizeof(MSG4) - 1) != sizeof(MSG4) - 1) + exit(0); + } + +#define MSG5 "\07\07That was the last time I'll tell you. Bye.\n" + (void)write(1, MSG5, sizeof(MSG5) - 1); + exit(0); +} + +usage() +{ + fprintf(stderr, "usage: leave [[+]hhmm]\n"); + exit(1); +} diff --git a/usr.bin/locate/Makefile b/usr.bin/locate/Makefile new file mode 100644 index 0000000..bc55dab --- /dev/null +++ b/usr.bin/locate/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +SUBDIR= bigram code locate + +.include diff --git a/usr.bin/locate/bigram/Makefile b/usr.bin/locate/bigram/Makefile new file mode 100644 index 0000000..d7d4348 --- /dev/null +++ b/usr.bin/locate/bigram/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= locate.bigram +NOMAN= noman +BINDIR= /usr/libexec + +.include diff --git a/usr.bin/locate/bigram/locate.bigram.c b/usr.bin/locate/bigram/locate.bigram.c new file mode 100644 index 0000000..b58fac4 --- /dev/null +++ b/usr.bin/locate/bigram/locate.bigram.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * bigram < text > bigrams + * + * List bigrams for 'updatedb' script. + * Use 'code' to encode a file using this output. + */ + +#include +#include /* for MAXPATHLEN */ + +char buf1[MAXPATHLEN] = " "; +char buf2[MAXPATHLEN]; + +main ( ) +{ + register char *cp; + register char *oldpath = buf1, *path = buf2; + + while ( fgets ( path, sizeof(buf2), stdin ) != NULL ) { + + /* skip longest common prefix */ + for ( cp = path; *cp == *oldpath; cp++, oldpath++ ) + if ( *oldpath == NULL ) + break; + /* + * output post-residue bigrams only + */ + while ( *cp != NULL && *(cp + 1) != NULL ) { + putchar ( *cp++ ); + putchar ( *cp++ ); + putchar ( '\n' ); + } + if ( path == buf1 ) /* swap pointers */ + path = buf2, oldpath = buf1; + else + path = buf1, oldpath = buf2; + } +} diff --git a/usr.bin/locate/code/Makefile b/usr.bin/locate/code/Makefile new file mode 100644 index 0000000..743e968 --- /dev/null +++ b/usr.bin/locate/code/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= locate.code +CFLAGS+=-I${.CURDIR}/../locate +NOMAN= noman +BINDIR= /usr/libexec + +.include diff --git a/usr.bin/locate/code/locate.code.c b/usr.bin/locate/code/locate.code.c new file mode 100644 index 0000000..d3ec29f --- /dev/null +++ b/usr.bin/locate/code/locate.code.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * PURPOSE: sorted list compressor (works with a modified 'find' + * to encode/decode a filename database) + * + * USAGE: bigram < list > bigrams + * process bigrams (see updatedb) > common_bigrams + * code common_bigrams < list > squozen_list + * + * METHOD: Uses 'front compression' (see ";login:", Volume 8, Number 1 + * February/March 1983, p. 8). Output format is, per line, an + * offset differential count byte followed by a partially bigram- + * encoded ascii residue. A bigram is a two-character sequence, + * the first 128 most common of which are encoded in one byte. + * + * EXAMPLE: For simple front compression with no bigram encoding, + * if the input is... then the output is... + * + * /usr/src 0 /usr/src + * /usr/src/cmd/aardvark.c 8 /cmd/aardvark.c + * /usr/src/cmd/armadillo.c 14 armadillo.c + * /usr/tmp/zoo 5 tmp/zoo + * + * The codes are: + * + * 0-28 likeliest differential counts + offset to make nonnegative + * 30 switch code for out-of-range count to follow in next word + * 128-255 bigram codes (128 most common, as determined by 'updatedb') + * 32-127 single character (printable) ascii residue (ie, literal) + * + * SEE ALSO: updatedb.csh, bigram.c + * + * AUTHOR: James A. Woods, Informatics General Corp., + * NASA Ames Research Center, 10/82 + */ + +#include +#include +#include +#include +#include +#include +#include "locate.h" + +#define BGBUFSIZE (NBG * 2) /* size of bigram buffer */ + +char buf1[MAXPATHLEN] = " "; +char buf2[MAXPATHLEN]; +char bigrams[BGBUFSIZE + 1] = { 0 }; + +int bgindex __P((char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char *cp, *oldpath, *path; + int ch, code, count, diffcount, oldcount; + FILE *fp; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if ((fp = fopen(argv[0], "r")) == NULL) + err(1, "%s", argv[0]); + + /* First copy bigram array to stdout. */ + (void)fgets(bigrams, BGBUFSIZE + 1, fp); + if (fwrite(bigrams, 1, BGBUFSIZE, stdout) != BGBUFSIZE) + err(1, "stdout"); + (void)fclose(fp); + + oldpath = buf1; + path = buf2; + oldcount = 0; + while (fgets(path, sizeof(buf2), stdin) != NULL) { + /* Truncate newline. */ + cp = path + strlen(path) - 1; + if (cp > path && *cp == '\n') + *cp = '\0'; + + /* Squelch characters that would botch the decoding. */ + for (cp = path; *cp != NULL; cp++) { + if ((u_char)*cp >= PARITY) + *cp &= PARITY-1; + else if (*cp <= SWITCH) + *cp = '?'; + } + + /* Skip longest common prefix. */ + for (cp = path; *cp == *oldpath; cp++, oldpath++) + if (*oldpath == NULL) + break; + count = cp - path; + diffcount = count - oldcount + OFFSET; + oldcount = count; + if (diffcount < 0 || diffcount > 2 * OFFSET) { + if (putchar(SWITCH) == EOF || + putw(diffcount, stdout) == EOF) + err(1, "stdout"); + } else + if (putchar(diffcount) == EOF) + err(1, "stdout"); + + while (*cp != NULL) { + if (*(cp + 1) == NULL) { + if (putchar(*cp) == EOF) + err(1, "stdout"); + break; + } + if ((code = bgindex(cp)) < 0) { + if (putchar(*cp++) == EOF || + putchar(*cp++) == EOF) + err(1, "stdout"); + } else { + /* Found, so mark byte with parity bit. */ + if (putchar((code / 2) | PARITY) == EOF) + err(1, "stdout"); + cp += 2; + } + } + if (path == buf1) { /* swap pointers */ + path = buf2; + oldpath = buf1; + } else { + path = buf1; + oldpath = buf2; + } + } + /* Non-zero status if there were errors */ + if (fflush(stdout) != 0 || ferror(stdout)) + exit(1); + exit(0); +} + +int +bgindex(bg) /* Return location of bg in bigrams or -1. */ + char *bg; +{ + register char bg0, bg1, *p; + + bg0 = bg[0]; + bg1 = bg[1]; + for (p = bigrams; *p != NULL; p++) + if (*p++ == bg0 && *p == bg1) + break; + return (*p == NULL ? -1 : --p - bigrams); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: locate.code common_bigrams < list > squozen_list\n"); + exit(1); +} diff --git a/usr.bin/locate/locate/Makefile b/usr.bin/locate/locate/Makefile new file mode 100644 index 0000000..2e6c696 --- /dev/null +++ b/usr.bin/locate/locate/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= locate + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/updatedb.csh ${DESTDIR}/usr/libexec/locate.updatedb + +.include "../../Makefile.inc" +.include diff --git a/usr.bin/locate/locate/locate.1 b/usr.bin/locate/locate/locate.1 new file mode 100644 index 0000000..89cc2e8 --- /dev/null +++ b/usr.bin/locate/locate/locate.1 @@ -0,0 +1,81 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)locate.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LOCATE 1 +.Os BSD 4.4 +.Sh NAME +.Nm locate +.Nd find files +.Sh SYNOPSIS +.Ar locate +pattern +.Sh DESCRIPTION +.Nm Locate +searches a database for all pathnames which match the specified +.Ar pattern . +The database is recomputed periodically, and contains the pathnames +of all files which are publicly accessible. +.Pp +Shell globbing and quoting characters (``*'', ``?'', ``\e'', ``['' +and ``]'') +may be used in +.Ar pattern , +although they will have to be escaped from the shell. +Preceding any character with a backslash (``\e'') eliminates any special +meaning which it may have. +The matching differs in that no characters must be matched explicitly, +including slashes (``/''). +.Pp +As a special case, a pattern containing no globbing characters (``foo'') +is matched as though it were ``*foo*''. +.Sh FILES +.Bl -tag -width /var/db/locate.database -compact +.It Pa /var/db/locate.database +.El +.Sh SEE ALSO +.Xr find 1 , +.Xr fnmatch 3 +.Rs +.%A Woods, James A. +.%D 1983 +.%T "Finding Files Fast" +.%J ";login" +.%V 8:1 +.%P pp. 8-10 +.Re +.Sh HISTORY +The +.Nm locate +command appears in +.Bx 4.4 . diff --git a/usr.bin/locate/locate/locate.c b/usr.bin/locate/locate/locate.c new file mode 100644 index 0000000..ea43872 --- /dev/null +++ b/usr.bin/locate/locate/locate.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Ref: Usenix ;login:, Vol 8, No 1, February/March, 1983, p. 8. + * + * Locate scans a file list for the full pathname of a file given only part + * of the name. The list has been processed with with "front-compression" + * and bigram coding. Front compression reduces space by a factor of 4-5, + * bigram coding by a further 20-25%. + * + * The codes are: + * + * 0-28 likeliest differential counts + offset to make nonnegative + * 30 switch code for out-of-range count to follow in next word + * 128-255 bigram codes (128 most common, as determined by 'updatedb') + * 32-127 single character (printable) ascii residue (ie, literal) + * + * A novel two-tiered string search technique is employed: + * + * First, a metacharacter-free subpattern and partial pathname is matched + * BACKWARDS to avoid full expansion of the pathname list. The time savings + * is 40-50% over forward matching, which cannot efficiently handle + * overlapped search patterns and compressed path residue. + * + * Then, the actual shell glob-style regular expression (if in this form) is + * matched against the candidate pathnames using the slower routines provided + * in the standard 'find'. + */ + +#include + +#include +#include +#include +#include + +#include "locate.h" +#include "pathnames.h" + +FILE *fp; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + if (argc != 2) { + (void)fprintf(stderr, "usage: locate pattern\n"); + exit(1); + } + if (!(fp = fopen(_PATH_FCODES, "r"))) { + (void)fprintf(stderr, "locate: no database file %s.\n", + _PATH_FCODES); + exit(1); + } + while (*++argv) + fastfind(*argv); + exit(0); +} + +fastfind(pathpart) + char *pathpart; +{ + register char *p, *s; + register int c; + int count, found, globflag; + char *cutoff, *patend, *q, *patprep(); + char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN]; + + for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) + p[c] = getc(fp), s[c] = getc(fp); + + p = pathpart; + globflag = index(p, '*') || index(p, '?') || index(p, '['); + patend = patprep(p); + + found = 0; + for (c = getc(fp), count = 0; c != EOF;) { + count += ((c == SWITCH) ? getw(fp) : c) - OFFSET; + /* overlay old path */ + for (p = path + count; (c = getc(fp)) > SWITCH;) + if (c < PARITY) + *p++ = c; + else { /* bigrams are parity-marked */ + c &= PARITY - 1; + *p++ = bigram1[c], *p++ = bigram2[c]; + } + *p-- = NULL; + cutoff = (found ? path : path + count); + for (found = 0, s = p; s >= cutoff; s--) + if (*s == *patend) { /* fast first char check */ + for (p = patend - 1, q = s - 1; *p != NULL; + p--, q--) + if (*q != *p) + break; + if (*p == NULL) { /* fast match success */ + found = 1; + if (!globflag || + !fnmatch(pathpart, path, 0)) + (void)printf("%s\n", path); + break; + } + } + } +} + +/* + * extract last glob-free subpattern in name for fast pre-match; prepend + * '\0' for backwards match; return end of new pattern + */ +static char globfree[100]; + +char * +patprep(name) + char *name; +{ + register char *endmark, *p, *subp; + + subp = globfree; + *subp++ = '\0'; + p = name + strlen(name) - 1; + /* skip trailing metacharacters (and [] ranges) */ + for (; p >= name; p--) + if (index("*?", *p) == 0) + break; + if (p < name) + p = name; + if (*p == ']') + for (p--; p >= name; p--) + if (*p == '[') { + p--; + break; + } + if (p < name) + p = name; + /* + * if pattern has only metacharacters, check every path (force '/' + * search) + */ + if ((p == name) && index("?*[]", *p) != 0) + *subp++ = '/'; + else { + for (endmark = p; p >= name; p--) + if (index("]*?", *p) != 0) + break; + for (++p; + (p <= endmark) && subp < (globfree + sizeof(globfree));) + *subp++ = *p++; + } + *subp = '\0'; + return(--subp); +} diff --git a/usr.bin/locate/locate/locate.h b/usr.bin/locate/locate/locate.h new file mode 100644 index 0000000..fe4da28 --- /dev/null +++ b/usr.bin/locate/locate/locate.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)locate.h 8.1 (Berkeley) 6/6/93 + */ + +/* Symbolic constants shared by locate.c and code.c */ + +#define NBG 128 /* number of bigrams considered */ +#define OFFSET 14 /* abs value of max likely diff */ +#define PARITY 0200 /* parity bit */ +#define SWITCH 30 /* switch code */ diff --git a/usr.bin/locate/locate/pathnames.h b/usr.bin/locate/locate/pathnames.h new file mode 100644 index 0000000..8fb0e8c --- /dev/null +++ b/usr.bin/locate/locate/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_FCODES "/var/db/locate.database" diff --git a/usr.bin/locate/locate/updatedb.csh b/usr.bin/locate/locate/updatedb.csh new file mode 100644 index 0000000..574d52a --- /dev/null +++ b/usr.bin/locate/locate/updatedb.csh @@ -0,0 +1,77 @@ +#!/bin/csh -f +# +# Copyright (c) 1989, 1993 +# The Regents of the University of California. All rights reserved. +# +# This code is derived from software contributed to Berkeley by +# James A. Woods. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)updatedb.csh 8.3 (Berkeley) 3/19/94 +# + +set SRCHPATHS = "/" # directories to be put in the database +set LIBDIR = /usr/libexec # for subprograms + # for temp files +if (! $?TMPDIR) setenv TMPDIR = /var/tmp +set FCODES = /var/db/locate.database # the database + +set path = ( /bin /usr/bin ) +set bigrams = $TMPDIR/locate.bigrams.$$ +set filelist = $TMPDIR/locate.list.$$ +set errs = $TMPDIR/locate.errs.$$ + +# Make a file list and compute common bigrams. +# Alphabetize '/' before any other char with 'tr'. +# If the system is very short of sort space, 'bigram' can be made +# smarter to accumulate common bigrams directly without sorting +# ('awk', with its associative memory capacity, can do this in several +# lines, but is too slow, and runs out of string space on small machines). + +# search locally or everything +# find ${SRCHPATHS} -print | \ +find ${SRCHPATHS} \! -fstype local -prune -or -print | \ + tr '/' '\001' | \ + (sort -T $TMPDIR -f; echo $status > $errs) | tr '\001' '/' > $filelist + +$LIBDIR/locate.bigram < $filelist | \ + (sort -T /$TMPDIR; echo $status >> $errs) | \ + uniq -c | sort -T /$TMPDIR -nr | \ + awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams + +# code the file list + +if { grep -s -v 0 $errs } then + printf 'locate: updatedb failed\n\n' +else + $LIBDIR/locate.code $bigrams < $filelist > $FCODES + chmod 644 $FCODES + rm $bigrams $filelist $errs +endif diff --git a/usr.bin/lock/Makefile b/usr.bin/lock/Makefile new file mode 100644 index 0000000..9403206 --- /dev/null +++ b/usr.bin/lock/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= lock +BINOWN= root +BINMODE=4555 + +.include diff --git a/usr.bin/lock/lock.1 b/usr.bin/lock/lock.1 new file mode 100644 index 0000000..ad8575c --- /dev/null +++ b/usr.bin/lock/lock.1 @@ -0,0 +1,68 @@ +.\" Copyright (c) 1987, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lock.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LOCK 1 +.Os +.Sh NAME +.Nm lock +.Nd reserve a terminal +.Sh SYNOPSIS +.Nm lock +.Op Fl p +.Op Fl t Ar timeout +.Sh DESCRIPTION +.Nm Lock +requests a password from the user, reads it again for verification +and then will normally not relinquish the terminal until the password is +repeated. +There are two other conditions under which it will terminate: it +will timeout after some interval of time and it may be killed by someone +with the appropriate permission. +.Pp +Options: +.Pp +.Bl -tag -width Fl +.It Fl p +A password is not requested, instead the user's current login password +is used. +.It Fl t Ar timeout +The time limit (default 15 minutes) is changed to +.Ar timeout +minutes. +.El +.Sh HISTORY +The +.Nm lock +command appeared in +.Bx 3.0 . diff --git a/usr.bin/lock/lock.c b/usr.bin/lock/lock.c new file mode 100644 index 0000000..774ebc9 --- /dev/null +++ b/usr.bin/lock/lock.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1980, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Bob Toxen. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1980, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)lock.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Lock a terminal up until the given key is entered, until the root + * password is entered, or the given interval times out. + * + * Timeout interval is by default TIMEOUT, it can be changed with + * an argument of the form -time where time is in minutes + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMEOUT 15 + +void quit(), bye(), hi(); + +struct timeval timeout; +struct timeval zerotime; +struct sgttyb tty, ntty; +long nexttime; /* keep the timeout time */ + +/*ARGSUSED*/ +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int errno, optind; + struct passwd *pw; + struct timeval timval; + struct itimerval ntimer, otimer; + struct tm *timp; + int ch, sectimeout, usemine; + char *ap, *mypw, *ttynam, *tzn; + char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ]; + char *crypt(), *ttyname(); + + sectimeout = TIMEOUT; + mypw = NULL; + usemine = 0; + while ((ch = getopt(argc, argv, "pt:")) != EOF) + switch((char)ch) { + case 't': + if ((sectimeout = atoi(optarg)) <= 0) { + (void)fprintf(stderr, + "lock: illegal timeout value.\n"); + exit(1); + } + break; + case 'p': + usemine = 1; + if (!(pw = getpwuid(getuid()))) { + (void)fprintf(stderr, + "lock: unknown uid %d.\n", getuid()); + exit(1); + } + mypw = strdup(pw->pw_passwd); + break; + case '?': + default: + (void)fprintf(stderr, + "usage: lock [-p] [-t timeout]\n"); + exit(1); + } + timeout.tv_sec = sectimeout * 60; + + setuid(getuid()); /* discard privs */ + + if (ioctl(0, TIOCGETP, &tty)) /* get information for header */ + exit(1); + gethostname(hostname, sizeof(hostname)); + if (!(ttynam = ttyname(0))) { + (void)printf("lock: not a terminal?\n"); + exit(1); + } + if (gettimeofday(&timval, (struct timezone *)NULL)) { + (void)fprintf(stderr, + "lock: gettimeofday: %s\n", strerror(errno)); + exit(1); + } + nexttime = timval.tv_sec + (sectimeout * 60); + timp = localtime(&timval.tv_sec); + ap = asctime(timp); + tzn = timp->tm_zone; + + (void)signal(SIGINT, quit); + (void)signal(SIGQUIT, quit); + ntty = tty; ntty.sg_flags &= ~ECHO; + (void)ioctl(0, TIOCSETP, &ntty); + + if (!mypw) { + /* get key and check again */ + (void)printf("Key: "); + if (!fgets(s, sizeof(s), stdin) || *s == '\n') + quit(); + (void)printf("\nAgain: "); + /* + * Don't need EOF test here, if we get EOF, then s1 != s + * and the right things will happen. + */ + (void)fgets(s1, sizeof(s1), stdin); + (void)putchar('\n'); + if (strcmp(s1, s)) { + (void)printf("\07lock: passwords didn't match.\n"); + ioctl(0, TIOCSETP, &tty); + exit(1); + } + s[0] = NULL; + mypw = s1; + } + + /* set signal handlers */ + (void)signal(SIGINT, hi); + (void)signal(SIGQUIT, hi); + (void)signal(SIGTSTP, hi); + (void)signal(SIGALRM, bye); + + ntimer.it_interval = zerotime; + ntimer.it_value = timeout; + setitimer(ITIMER_REAL, &ntimer, &otimer); + + /* header info */ +(void)printf("lock: %s on %s. timeout in %d minutes\ntime now is %.20s%s%s", + ttynam, hostname, sectimeout, ap, tzn, ap + 19); + + for (;;) { + (void)printf("Key: "); + if (!fgets(s, sizeof(s), stdin)) { + clearerr(stdin); + hi(); + continue; + } + if (usemine) { + s[strlen(s) - 1] = '\0'; + if (!strcmp(mypw, crypt(s, mypw))) + break; + } + else if (!strcmp(s, s1)) + break; + (void)printf("\07\n"); + if (ioctl(0, TIOCGETP, &ntty)) + exit(1); + } + quit(); +} + +void +hi() +{ + struct timeval timval; + + if (!gettimeofday(&timval, (struct timezone *)NULL)) +(void)printf("lock: type in the unlock key. timeout in %ld:%ld minutes\n", + (nexttime - timval.tv_sec) / 60, (nexttime - timval.tv_sec) % 60); +} + +void +quit() +{ + (void)putchar('\n'); + (void)ioctl(0, TIOCSETP, &tty); + exit(0); +} + +void +bye() +{ + (void)ioctl(0, TIOCSETP, &tty); + (void)printf("lock: timeout\n"); + exit(1); +} diff --git a/usr.bin/logger/Makefile b/usr.bin/logger/Makefile new file mode 100644 index 0000000..a5d143b --- /dev/null +++ b/usr.bin/logger/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= logger + +.include diff --git a/usr.bin/logger/logger.1 b/usr.bin/logger/logger.1 new file mode 100644 index 0000000..0621dba --- /dev/null +++ b/usr.bin/logger/logger.1 @@ -0,0 +1,100 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)logger.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LOGGER 1 +.Os BSD 4.3 +.Sh NAME +.Nm logger +.Nd make entries in the system log +.Sh SYNOPSIS +.Nm logger +.Op Fl is +.Op Fl f Ar file +.Op Fl p Ar pri +.Op Fl t Ar tag +.Op Ar message ... +.Sh DESCRIPTION +.Nm Logger +provides a shell command interface to the +.Xr syslog 3 +system log module. +.Pp +Options: +.Pp +.Bl -tag -width "message" +.It Fl i +Log the process id of the logger process +with each line. +.It Fl s +Log the message to standard error, as well as the system log. +.It Fl f Ar file +Log the specified file. +.It Fl p Ar pri +Enter the message with the specified priority. +The priority may be specified numerically or as a ``facility.level'' +pair. +For example, ``\-p local3.info'' logs the message(s) as +.Ar info Ns rmational +level in the +.Ar local3 +facility. +The default is ``user.notice.'' +.It Fl t Ar tag +Mark every line in the log with the specified +.Ar tag . +.It Ar message +Write the message to log; if not specified, and the +.Fl f +flag is not +provided, standard input is logged. +.El +.Pp +The +.Nm logger +utility exits 0 on success, and >0 if an error occurs. +.Sh EXAMPLES +.Bd -literal -offset indent -compact +logger System rebooted + +logger \-p local0.notice \-t HOSTIDM \-f /dev/idmc +.Ed +.Sh SEE ALSO +.Xr syslog 3 , +.Xr syslogd 8 +.Sh STANDARDS +The +.Nm logger +command is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/logger/logger.c b/usr.bin/logger/logger.c new file mode 100644 index 0000000..3fd3b6b --- /dev/null +++ b/usr.bin/logger/logger.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#define SYSLOG_NAMES +#include + +int decode __P((char *, CODE *)); +int pencode __P((char *)); +void usage __P((void)); + +/* + * logger -- read and log utility + * + * Reads from an input and arranges to write the result on the system + * log. + */ +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, logflags, pri; + char *tag, buf[1024]; + + tag = NULL; + pri = LOG_NOTICE; + logflags = 0; + while ((ch = getopt(argc, argv, "f:ip:st:")) != EOF) + switch((char)ch) { + case 'f': /* file to log */ + if (freopen(optarg, "r", stdin) == NULL) { + (void)fprintf(stderr, "logger: %s: %s.\n", + optarg, strerror(errno)); + exit(1); + } + break; + case 'i': /* log process id also */ + logflags |= LOG_PID; + break; + case 'p': /* priority */ + pri = pencode(optarg); + break; + case 's': /* log to standard error */ + logflags |= LOG_PERROR; + break; + case 't': /* tag */ + tag = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* setup for logging */ + openlog(tag ? tag : getlogin(), logflags, 0); + (void) fclose(stdout); + + /* log input line if appropriate */ + if (argc > 0) { + register char *p, *endp; + int len; + + for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { + len = strlen(*argv); + if (p + len > endp && p > buf) { + syslog(pri, "%s", buf); + p = buf; + } + if (len > sizeof(buf) - 1) + syslog(pri, "%s", *argv++); + else { + if (p != buf) + *p++ = ' '; + bcopy(*argv++, p, len); + *(p += len) = '\0'; + } + } + if (p != buf) + syslog(pri, "%s", buf); + } else + while (fgets(buf, sizeof(buf), stdin) != NULL) + syslog(pri, "%s", buf); + exit(0); +} + +/* + * Decode a symbolic name to a numeric value + */ +int +pencode(s) + register char *s; +{ + char *save; + int fac, lev; + + for (save = s; *s && *s != '.'; ++s); + if (*s) { + *s = '\0'; + fac = decode(save, facilitynames); + if (fac < 0) { + (void)fprintf(stderr, + "logger: unknown facility name: %s.\n", save); + exit(1); + } + *s++ = '.'; + } + else { + fac = 0; + s = save; + } + lev = decode(s, prioritynames); + if (lev < 0) { + (void)fprintf(stderr, + "logger: unknown priority name: %s.\n", save); + exit(1); + } + return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); +} + +int +decode(name, codetab) + char *name; + CODE *codetab; +{ + register CODE *c; + + if (isdigit(*name)) + return (atoi(name)); + + for (c = codetab; c->c_name; c++) + if (!strcasecmp(name, c->c_name)) + return (c->c_val); + + return (-1); +} + +void +usage() +{ + (void)fprintf(stderr, + "logger: [-is] [-f file] [-p pri] [-t tag] [ message ... ]\n"); + exit(1); +} diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile new file mode 100644 index 0000000..a11fbc0 --- /dev/null +++ b/usr.bin/login/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 7/19/93 + +CFLAGS+=-DKERBEROS +PROG= login +SRCS= klogin.c login.c +DPADD= ${LIBUTIL} ${LIBKRB} ${LIBDES} +LDADD= -lutil -lkrb -ldes +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg + +.include diff --git a/usr.bin/login/klogin.c b/usr.bin/login/klogin.c new file mode 100644 index 0000000..6601a6e --- /dev/null +++ b/usr.bin/login/klogin.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)klogin.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#ifdef KERBEROS +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define INITIAL_TICKET "krbtgt" +#define VERIFY_SERVICE "rcmd" + +extern int notickets; +extern char *krbtkfile_env; + +/* + * Attempt to log the user in using Kerberos authentication + * + * return 0 on success (will be logged in) + * 1 if Kerberos failed (try local password in login) + */ +int +klogin(pw, instance, localhost, password) + struct passwd *pw; + char *instance, *localhost, *password; +{ + int kerror; + AUTH_DAT authdata; + KTEXT_ST ticket; + struct hostent *hp; + unsigned long faddr; + char realm[REALM_SZ], savehost[MAXHOSTNAMELEN]; + char tkt_location[MAXPATHLEN]; + char *krb_get_phost(); + + /* + * Root logins don't use Kerberos. + * If we have a realm, try getting a ticket-granting ticket + * and using it to authenticate. Otherwise, return + * failure so that we can try the normal passwd file + * for a password. If that's ok, log the user in + * without issuing any tickets. + */ + if (strcmp(pw->pw_name, "root") == 0 || + krb_get_lrealm(realm, 0) != KSUCCESS) + return (1); + + /* + * get TGT for local realm + * tickets are stored in a file named TKT_ROOT plus uid + * except for user.root tickets. + */ + + if (strcmp(instance, "root") != 0) + (void)sprintf(tkt_location, "%s%d", TKT_ROOT, pw->pw_uid); + else { + (void)sprintf(tkt_location, "%s_root_%d", TKT_ROOT, pw->pw_uid); + krbtkfile_env = tkt_location; + } + (void)krb_set_tkt_string(tkt_location); + + /* + * Set real as well as effective ID to 0 for the moment, + * to make the kerberos library do the right thing. + */ + if (setuid(0) < 0) { + warnx("setuid"); + return (1); + } + kerror = krb_get_pw_in_tkt(pw->pw_name, instance, + realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password); + /* + * If we got a TGT, get a local "rcmd" ticket and check it so as to + * ensure that we are not talking to a bogus Kerberos server. + * + * There are 2 cases where we still allow a login: + * 1: the VERIFY_SERVICE doesn't exist in the KDC + * 2: local host has no srvtab, as (hopefully) indicated by a + * return value of RD_AP_UNDEC from krb_rd_req(). + */ + if (kerror != INTK_OK) { + if (kerror != INTK_BADPW && kerror != KDC_PR_UNKNOWN) { + syslog(LOG_ERR, "Kerberos intkt error: %s", + krb_err_txt[kerror]); + dest_tkt(); + } + return (1); + } + + if (chown(TKT_FILE, pw->pw_uid, pw->pw_gid) < 0) + syslog(LOG_ERR, "chown tkfile (%s): %m", TKT_FILE); + + (void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost)); + savehost[sizeof(savehost)-1] = NULL; + + /* + * if the "VERIFY_SERVICE" doesn't exist in the KDC for this host, + * still allow login with tickets, but log the error condition. + */ + + kerror = krb_mk_req(&ticket, VERIFY_SERVICE, savehost, realm, 33); + if (kerror == KDC_PR_UNKNOWN) { + syslog(LOG_NOTICE, + "warning: TGT not verified (%s); %s.%s not registered, or srvtab is wrong?", + krb_err_txt[kerror], VERIFY_SERVICE, savehost); + notickets = 0; + return (0); + } + + if (kerror != KSUCCESS) { + warnx("unable to use TGT: (%s)", krb_err_txt[kerror]); + syslog(LOG_NOTICE, "unable to use TGT: (%s)", + krb_err_txt[kerror]); + dest_tkt(); + return (1); + } + + if (!(hp = gethostbyname(localhost))) { + syslog(LOG_ERR, "couldn't get local host address"); + dest_tkt(); + return (1); + } + + memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); + + kerror = krb_rd_req(&ticket, VERIFY_SERVICE, savehost, faddr, + &authdata, ""); + + if (kerror == KSUCCESS) { + notickets = 0; + return (0); + } + + /* undecipherable: probably didn't have a srvtab on the local host */ + if (kerror = RD_AP_UNDEC) { + syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]); + dest_tkt(); + return (1); + } + /* failed for some other reason */ + warnx("unable to verify %s ticket: (%s)", VERIFY_SERVICE, + krb_err_txt[kerror]); + syslog(LOG_NOTICE, "couldn't verify %s ticket: %s", VERIFY_SERVICE, + krb_err_txt[kerror]); + dest_tkt(); + return (1); +} +#endif diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1 new file mode 100644 index 0000000..db59c1a --- /dev/null +++ b/usr.bin/login/login.1 @@ -0,0 +1,146 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)login.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt LOGIN 1 +.Os BSD 4 +.Sh NAME +.Nm login +.Nd log into the computer +.Sh SYNOPSIS +.Nm login +.Op Fl fp +.Op Fl h Ar hostname +.Op Ar user +.Sh DESCRIPTION +The +.Nm login +utility logs users (and pseudo-users) into the computer system. +.Pp +If no user is specified, or if a user is specified and authentication +of the user fails, +.Nm login +prompts for a user name. +Authentication of users is done via passwords. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f +The +.Fl f +option is used when a user name is specified to indicate that proper +authentication has already been done and that no password need be +requested. +This option may only be used by the super-user or when an already +logged in user is logging in as themselves. +.It Fl h +The +.Fl h +option specifies the host from which the connection was received. +It is used by various daemons such as +.Xr telnetd 8 . +This option may only be used by the super-user. +.It Fl p +By default, +.Nm login +discards any previous environment. +The +.Fl p +option disables this behavior. +.El +.Pp +If the file +.Pa /etc/nologin +exists, +.Nm login +dislays its contents to the user and exits. +This is used by +.Xr shutdown 8 +to prevent users from logging in when the system is about to go down. +.Pp +Immediately after logging a user in, +.Nm login +displays the system copyright notice, the date and time the user last +logged in, the message of the day as well as other information. +If the file +.Dq Pa .hushlogin +exists in the user's home directory, all of these messages are suppressed. +This is to simplify logins for non-human users, such as +.Xr uucp 1 . +.Nm Login +then records an entry in the +.Xr wtmp 5 +and +.Xr utmp 5 +files and executes the user's command interpretor. +.Pp +Login enters information into the environment (see +.Xr environ 7 ) +specifying the user's home directory (HOME), command interpreter (SHELL), +search path (PATH), terminal type (TERM) and user name (both LOGNAME and +USER). +.Pp +The standard shells, +.Xr csh 1 +and +.Xr sh 1 , +do not fork before executing the +.Nm login +utility. +.Sh FILES +.Bl -tag -width /var/mail/userXXX -compact +.It Pa /etc/motd +message-of-the-day +.It Pa /etc/nologin +disallows logins +.It Pa /var/run/utmp +current logins +.It Pa /var/log/wtmp +login account records +.It Pa /var/mail/user +system mailboxes +.It Pa \&.hushlogin +makes login quieter +.El +.Sh SEE ALSO +.Xr chpass 1 , +.Xr passwd 1 , +.Xr rlogin 1 , +.Xr getpass 3 , +.Xr utmp 5 , +.Xr environ 7 , +.Sh HISTORY +A +.Nm login +appeared in +.At v6 . diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c new file mode 100644 index 0000000..ef75733 --- /dev/null +++ b/usr.bin/login/login.c @@ -0,0 +1,594 @@ +/*- + * Copyright (c) 1980, 1987, 1988, 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 copyright[] = +"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * login [ name ] + * login -h hostname (for telnetd, etc.) + * login -f name (for pre-authenticated login: datakit, xterm, etc.) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +void badlogin __P((char *)); +void checknologin __P((void)); +void dolastlog __P((int)); +void getloginname __P((void)); +void motd __P((void)); +int rootterm __P((char *)); +void sigint __P((int)); +void sleepexit __P((int)); +char *stypeof __P((char *)); +void timedout __P((int)); +#ifdef KERBEROS +int klogin __P((struct passwd *, char *, char *, char *)); +#endif + +extern void login __P((struct utmp *)); + +#define TTYGRPNAME "tty" /* name of group to own ttys */ + +/* + * This bounds the time given to login. Not a define so it can + * be patched on machines where it's too small. + */ +u_int timeout = 300; + +#ifdef KERBEROS +int notickets = 1; +char *instance; +char *krbtkfile_env; +int authok; +#endif + +struct passwd *pwd; +int failures; +char term[64], *envinit[1], *hostname, *username, *tty; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char **environ; + struct group *gr; + struct stat st; + struct timeval tp; + struct utmp utmp; + int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; + uid_t uid; + char *domain, *p, *salt, *ttyn; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char localhost[MAXHOSTNAMELEN]; + + (void)signal(SIGALRM, timedout); + (void)alarm(timeout); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)setpriority(PRIO_PROCESS, 0, 0); + + openlog("login", LOG_ODELAY, LOG_AUTH); + + /* + * -p is used by getty to tell login not to destroy the environment + * -f is used to skip a second login authentication + * -h is used by other servers to pass the name of the remote + * host to login so that it may be placed in utmp and wtmp + */ + domain = NULL; + if (gethostname(localhost, sizeof(localhost)) < 0) + syslog(LOG_ERR, "couldn't get local hostname: %m"); + else + domain = strchr(localhost, '.'); + + fflag = hflag = pflag = 0; + uid = getuid(); + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { + case 'f': + fflag = 1; + break; + case 'h': + if (uid) + errx(1, "-h option: %s", strerror(EPERM)); + hflag = 1; + if (domain && (p = strchr(optarg, '.')) && + strcasecmp(p, domain) == 0) + *p = 0; + hostname = optarg; + break; + case 'p': + pflag = 1; + break; + case '?': + default: + if (!uid) + syslog(LOG_ERR, "invalid flag %c", ch); + (void)fprintf(stderr, + "usage: login [-fp] [-h hostname] [username]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + if (*argv) { + username = *argv; + ask = 0; + } else + ask = 1; + + for (cnt = getdtablesize(); cnt > 2; cnt--) + (void)close(cnt); + + ttyn = ttyname(STDIN_FILENO); + if (ttyn == NULL || *ttyn == '\0') { + (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); + ttyn = tname; + } + if (tty = strrchr(ttyn, '/')) + ++tty; + else + tty = ttyn; + + for (cnt = 0;; ask = 1) { + if (ask) { + fflag = 0; + getloginname(); + } + rootlogin = 0; +#ifdef KERBEROS + if ((instance = strchr(username, '.')) != NULL) { + if (strncmp(instance, ".root", 5) == 0) + rootlogin = 1; + *instance++ = '\0'; + } else + instance = ""; +#endif + if (strlen(username) > UT_NAMESIZE) + username[UT_NAMESIZE] = '\0'; + + /* + * Note if trying multiple user names; log failures for + * previous user name, but don't bother logging one failure + * for nonexistent name (mistyped username). + */ + if (failures && strcmp(tbuf, username)) { + if (failures > (pwd ? 0 : 1)) + badlogin(tbuf); + failures = 0; + } + (void)strcpy(tbuf, username); + + if (pwd = getpwnam(username)) + salt = pwd->pw_passwd; + else + salt = "xx"; + + /* + * if we have a valid account name, and it doesn't have a + * password, or the -f option was specified and the caller + * is root or the caller isn't changing their uid, don't + * authenticate. + */ + if (pwd && (*pwd->pw_passwd == '\0' || + fflag && (uid == 0 || uid == pwd->pw_uid))) + break; + fflag = 0; + if (pwd && pwd->pw_uid == 0) + rootlogin = 1; + + (void)setpriority(PRIO_PROCESS, 0, -4); + + p = getpass("Password:"); + + if (pwd) { +#ifdef KERBEROS + rval = klogin(pwd, instance, localhost, p); + if (rval != 0 && rootlogin && pwd->pw_uid != 0) + rootlogin = 0; + if (rval == 0) + authok = 1; + else if (rval == 1) + rval = strcmp(crypt(p, salt), pwd->pw_passwd); +#else + rval = strcmp(crypt(p, salt), pwd->pw_passwd); +#endif + } + memset(p, 0, strlen(p)); + + (void)setpriority(PRIO_PROCESS, 0, 0); + + /* + * If trying to log in as root without Kerberos, + * but with insecure terminal, refuse the login attempt. + */ +#ifdef KERBEROS + if (authok == 0) +#endif + if (pwd && rootlogin && !rootterm(tty)) { + (void)fprintf(stderr, + "%s login refused on this terminal.\n", + pwd->pw_name); + if (hostname) + syslog(LOG_NOTICE, + "LOGIN %s REFUSED FROM %s ON TTY %s", + pwd->pw_name, hostname, tty); + else + syslog(LOG_NOTICE, + "LOGIN %s REFUSED ON TTY %s", + pwd->pw_name, tty); + continue; + } + + if (pwd && !rval) + break; + + (void)printf("Login incorrect\n"); + failures++; + /* we allow 10 tries, but after 3 we start backing off */ + if (++cnt > 3) { + if (cnt >= 10) { + badlogin(username); + sleepexit(1); + } + sleep((u_int)((cnt - 3) * 5)); + } + } + + /* committed to login -- turn off timeout */ + (void)alarm((u_int)0); + + endpwent(); + + /* if user not super-user, check for disabled logins */ + if (!rootlogin) + checknologin(); + + if (chdir(pwd->pw_dir) < 0) { + (void)printf("No home directory %s!\n", pwd->pw_dir); + if (chdir("/")) + exit(0); + pwd->pw_dir = "/"; + (void)printf("Logging in with home = \"/\".\n"); + } + + quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; + + if (pwd->pw_change || pwd->pw_expire) + (void)gettimeofday(&tp, (struct timezone *)NULL); + if (pwd->pw_change) + if (tp.tv_sec >= pwd->pw_change) { + (void)printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } else if (pwd->pw_change - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your password expires on %s", + ctime(&pwd->pw_change)); + if (pwd->pw_expire) + if (tp.tv_sec >= pwd->pw_expire) { + (void)printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } else if (pwd->pw_expire - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your account expires on %s", + ctime(&pwd->pw_expire)); + + /* Nothing else left to fail -- really log in. */ + memset((void *)&utmp, 0, sizeof(utmp)); + (void)time(&utmp.ut_time); + (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + if (hostname) + (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + login(&utmp); + + dolastlog(quietlog); + + (void)chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + (void)setgid(pwd->pw_gid); + + initgroups(username, pwd->pw_gid); + + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; + + /* Destroy environment unless user has requested its preservation. */ + if (!pflag) + environ = envinit; + (void)setenv("HOME", pwd->pw_dir, 1); + (void)setenv("SHELL", pwd->pw_shell, 1); + if (term[0] == '\0') + (void)strncpy(term, stypeof(tty), sizeof(term)); + (void)setenv("TERM", term, 0); + (void)setenv("LOGNAME", pwd->pw_name, 1); + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("PATH", _PATH_DEFPATH, 0); +#ifdef KERBEROS + if (krbtkfile_env) + (void)setenv("KRBTKFILE", krbtkfile_env, 1); +#endif + + if (tty[sizeof("tty")-1] == 'd') + syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); + + /* If fflag is on, assume caller/authenticator has logged root login. */ + if (rootlogin && fflag == 0) + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", + username, tty, hostname); + else + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); + +#ifdef KERBEROS + if (!quietlog && notickets == 1) + (void)printf("Warning: no Kerberos tickets issued.\n"); +#endif + + if (!quietlog) { + (void)printf("%s\n\t%s %s\n\n", + "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", + "The Regents of the University of California. ", + "All rights reserved."); + motd(); + (void)snprintf(tbuf, + sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + (void)printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); + } + + (void)signal(SIGALRM, SIG_DFL); + (void)signal(SIGQUIT, SIG_DFL); + (void)signal(SIGINT, SIG_DFL); + (void)signal(SIGTSTP, SIG_IGN); + + tbuf[0] = '-'; + (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell); + + if (setlogin(pwd->pw_name) < 0) + syslog(LOG_ERR, "setlogin() failure: %m"); + + /* Discard permissions last so can't get killed and drop core. */ + if (rootlogin) + (void) setuid(0); + else + (void) setuid(pwd->pw_uid); + + execlp(pwd->pw_shell, tbuf, 0); + err(1, "%s", pwd->pw_shell); +} + +#ifdef KERBEROS +#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ +#else +#define NBUFSIZ (UT_NAMESIZE + 1) +#endif + +void +getloginname() +{ + int ch; + char *p; + static char nbuf[NBUFSIZ]; + + for (;;) { + (void)printf("login: "); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin(username); + exit(0); + } + if (p < nbuf + (NBUFSIZ - 1)) + *p++ = ch; + } + if (p > nbuf) + if (nbuf[0] == '-') + (void)fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + } +} + +int +rootterm(ttyn) + char *ttyn; +{ + struct ttyent *t; + + return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); +} + +jmp_buf motdinterrupt; + +void +motd() +{ + int fd, nchars; + sig_t oldint; + char tbuf[8192]; + + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) + return; + oldint = signal(SIGINT, sigint); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + (void)signal(SIGINT, oldint); + (void)close(fd); +} + +/* ARGSUSED */ +void +sigint(signo) + int signo; +{ + + longjmp(motdinterrupt, 1); +} + +/* ARGSUSED */ +void +timedout(signo) + int signo; +{ + + (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); + exit(0); +} + +void +checknologin() +{ + int fd, nchars; + char tbuf[8192]; + + if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + sleepexit(0); + } +} + +void +dolastlog(quiet) + int quiet; +{ + struct lastlog ll; + int fd; + + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + if (!quiet) { + if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && + ll.ll_time != 0) { + (void)printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + if (*ll.ll_host != '\0') + (void)printf("from %.*s\n", + (int)sizeof(ll.ll_host), + ll.ll_host); + else + (void)printf("on %.*s\n", + (int)sizeof(ll.ll_line), + ll.ll_line); + } + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + } + memset((void *)&ll, 0, sizeof(ll)); + (void)time(&ll.ll_time); + (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + (void)write(fd, (char *)&ll, sizeof(ll)); + (void)close(fd); + } +} + +void +badlogin(name) + char *name; +{ + + if (failures == 0) + return; + if (hostname) { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", + failures, failures > 1 ? "S" : "", hostname); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s FROM %s, %s", + failures, failures > 1 ? "S" : "", hostname, name); + } else { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", + failures, failures > 1 ? "S" : "", tty); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); + } +} + +#undef UNKNOWN +#define UNKNOWN "su" + +char * +stypeof(ttyid) + char *ttyid; +{ + struct ttyent *t; + + return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); +} + +void +sleepexit(eval) + int eval; +{ + + (void)sleep(5); + exit(eval); +} diff --git a/usr.bin/login/pathnames.h b/usr.bin/login/pathnames.h new file mode 100644 index 0000000..a9e1a077 --- /dev/null +++ b/usr.bin/login/pathnames.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/9/93 + */ + +#include + +#define _PATH_HUSHLOGIN ".hushlogin" +#define _PATH_MOTDFILE "/etc/motd" diff --git a/usr.bin/logname/Makefile b/usr.bin/logname/Makefile new file mode 100644 index 0000000..b8471ce --- /dev/null +++ b/usr.bin/logname/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= logname + +.include diff --git a/usr.bin/logname/logname.1 b/usr.bin/logname/logname.1 new file mode 100644 index 0000000..fbcdb3c --- /dev/null +++ b/usr.bin/logname/logname.1 @@ -0,0 +1,76 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)logname.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd "June 9, 1993" +.Dt LOGNAME 1 +.Os BSD 4.4 +.Sh NAME +.Nm logname +.Nd display user's login name +.Sh SYNOPSIS +.Nm logname +.Sh DESCRIPTION +The +.Nm logname +utility writes the user's login name to standard output followed by +a newline. +.Pp +The +.Nm logname +utility explicitly ignores the +.Ev LOGNAME +and +.Ev USER +environment variables +because the environment cannot be trusted. +.Pp +The +.Nm logname +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr who 1 , +.Xr whoami 1 , +.Xr getlogin 3 +.Sh STANDARDS +The +.Nm logname +function is expected to conform to +.St -p1003.2 . +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/logname/logname.c b/usr.bin/logname/logname.c new file mode 100644 index 0000000..98b948a --- /dev/null +++ b/usr.bin/logname/logname.c @@ -0,0 +1,81 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)logname.c 8.2 (Berkeley) 4/3/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch; + char *p; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if ((p = getlogin()) == NULL) + err(1, NULL); + (void)printf("%s\n", p); + exit(0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: logname\n"); + exit(1); +} diff --git a/usr.bin/look/Makefile b/usr.bin/look/Makefile new file mode 100644 index 0000000..64d7788 --- /dev/null +++ b/usr.bin/look/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= look + +.include diff --git a/usr.bin/look/look.1 b/usr.bin/look/look.1 new file mode 100644 index 0000000..3d8a247 --- /dev/null +++ b/usr.bin/look/look.1 @@ -0,0 +1,104 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)look.1 8.1 (Berkeley) 6/14/93 +.\" +.Dd June 14, 1993 +.Dt LOOK 1 +.Os +.Sh NAME +.Nm look +.Nd display lines beginning with a given string +.Sh SYNOPSIS +.Nm look +.Op Fl df +.Op Fl t Ar termchar +.Ar string +.Op Ar file +.Sh DESCRIPTION +The +.Nm look +utility displays any lines in +.Ar file +which contain +.Ar string +as a prefix. +As +.Nm look +performs a binary search, the lines in +.Ar file +must be sorted. +.Pp +If +.Ar file +is not specified, the file +.Pa /usr/share/dict/words +is used, only alphanumeric characters are compared and the case of +alphabetic characters is ignored. +.Pp +Options: +.Bl -tag -width Ds +.It Fl d +Dictionary character set and order, i.e. only alphanumeric characters +are compared. +.It Fl f +Ignore the case of alphabetic characters. +.It Fl t +Specify a string termination character, i.e. only the characters +in +.Ar string +up to and including the first occurrence of +.Ar termchar +are compared. +.El +.Pp +The +.Nm look +utility exits 0 if one or more lines were found and displayed, +1 if no lines were found, and >1 if an error occurred. +.Sh FILES +.Bl -tag -width /usr/share/dict/words -compact +.It Pa /usr/share/dict/words +the dictionary +.El +.Sh SEE ALSO +.Xr grep 1 , +.Xr sort 1 +.Sh COMPATIBILITY +The original manual page stated that tabs and blank characters participated +in comparisons when the +.Fl d +option was specified. +This was incorrect and the current man page matches the historic +implementation. +.Sh HISTORY +.Nm Look +appeared in Version 7 AT&T Unix. diff --git a/usr.bin/look/look.c b/usr.bin/look/look.c new file mode 100644 index 0000000..87db927 --- /dev/null +++ b/usr.bin/look/look.c @@ -0,0 +1,357 @@ +/*- + * Copyright (c) 1991, 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 copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/14/93"; +#endif /* not lint */ + +/* + * look -- find lines in a sorted list. + * + * The man page said that TABs and SPACEs participate in -d comparisons. + * In fact, they were ignored. This implements historic practice, not + * the manual page. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +/* + * FOLD and DICT convert characters to a normal form for comparison, + * according to the user specified flags. + * + * DICT expects integers because it uses a non-character value to + * indicate a character which should not participate in comparisons. + */ +#define EQUAL 0 +#define GREATER 1 +#define LESS (-1) +#define NO_COMPARE (-2) + +#define FOLD(c) (isascii(c) && isupper(c) ? tolower(c) : (c)) +#define DICT(c) (isascii(c) && isalnum(c) ? (c) : NO_COMPARE) + +int dflag, fflag; + +char *binary_search __P((char *, char *, char *)); +int compare __P((char *, char *, char *)); +void err __P((const char *fmt, ...)); +char *linear_search __P((char *, char *, char *)); +int look __P((char *, char *, char *)); +void print_from __P((char *, char *, char *)); + +static void usage __P((void)); + +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb; + int ch, fd, termchar; + char *back, *file, *front, *string, *p; + + file = _PATH_WORDS; + termchar = '\0'; + while ((ch = getopt(argc, argv, "dft:")) != EOF) + switch(ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + break; + case 't': + termchar = *optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch (argc) { + case 2: /* Don't set -df for user. */ + string = *argv++; + file = *argv; + break; + case 1: /* But set -df by default. */ + dflag = fflag = 1; + string = *argv; + break; + default: + usage(); + } + + if (termchar != '\0' && (p = strchr(string, termchar)) != NULL) + *++p = '\0'; + + if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb)) + err("%s: %s", file, strerror(errno)); + if (sb.st_size > SIZE_T_MAX) + err("%s: %s", file, strerror(EFBIG)); + if ((front = mmap(NULL, + (size_t)sb.st_size, PROT_READ, 0, fd, (off_t)0)) == NULL) + err("%s: %s", file, strerror(errno)); + back = front + sb.st_size; + exit(look(string, front, back)); +} + +look(string, front, back) + char *string, *front, *back; +{ + register int ch; + register char *readp, *writep; + + /* Reformat string string to avoid doing it multiple times later. */ + for (readp = writep = string; ch = *readp++;) { + if (fflag) + ch = FOLD(ch); + if (dflag) + ch = DICT(ch); + if (ch != NO_COMPARE) + *(writep++) = ch; + } + *writep = '\0'; + + front = binary_search(string, front, back); + front = linear_search(string, front, back); + + if (front) + print_from(string, front, back); + return (front ? 0 : 1); +} + + +/* + * 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'); + +char * +binary_search(string, front, back) + register char *string, *front, *back; +{ + register char *p; + + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + + /* + * If the file changes underneath us, make sure we don't + * infinitely loop. + */ + while (p < back && back > front) { + 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. + */ +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); +} + +/* + * Print as many lines as match string, starting at front. + */ +void +print_from(string, front, back) + register char *string, *front, *back; +{ + for (; front < back && compare(string, front, back) == EQUAL; ++front) { + for (; front < back && *front != '\n'; ++front) + if (putchar(*front) == EOF) + err("stdout: %s", strerror(errno)); + if (putchar('\n') == EOF) + err("stdout: %s", strerror(errno)); + } +} + +/* + * 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. + * + * Compare understands about the -f and -d flags, and treats comparisons + * appropriately. + * + * The string "s1" is null terminated. The string s2 is '\n' terminated (or + * "back" terminated). + */ +int +compare(s1, s2, back) + register char *s1, *s2, *back; +{ + register int ch; + + for (; *s1 && s2 < back && *s2 != '\n'; ++s1, ++s2) { + ch = *s2; + if (fflag) + ch = FOLD(ch); + if (dflag) + ch = DICT(ch); + + if (ch == NO_COMPARE) { + ++s2; /* Ignore character in comparison. */ + continue; + } + if (*s1 != ch) + return (*s1 < ch ? LESS : GREATER); + } + return (*s1 ? GREATER : EQUAL); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: look [-df] [-t char] string [file]\n"); + exit(2); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "look: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(2); + /* NOTREACHED */ +} diff --git a/usr.bin/look/pathnames.h b/usr.bin/look/pathnames.h new file mode 100644 index 0000000..586e36a --- /dev/null +++ b/usr.bin/look/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/9/93 + */ + +#define _PATH_WORDS "/usr/share/dict/words" diff --git a/usr.bin/lorder/Makefile b/usr.bin/lorder/Makefile new file mode 100644 index 0000000..70d28f5 --- /dev/null +++ b/usr.bin/lorder/Makefile @@ -0,0 +1,17 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +MAN1= lorder.0 + +all lorder: ${MAN1} + +clean depend lint tags: + +cleandir: + rm -f ${MAN1} + +install: maninstall + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/lorder.sh ${DESTDIR}/${BINDIR}/lorder + +.include +.include diff --git a/usr.bin/lorder/lorder.1 b/usr.bin/lorder/lorder.1 new file mode 100644 index 0000000..b5bfd57 --- /dev/null +++ b/usr.bin/lorder/lorder.1 @@ -0,0 +1,73 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)lorder.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LORDER 1 +.Os +.Sh NAME +.Nm lorder +.Nd list dependencies for object files +.Sh SYNOPSIS +.Nm lorder +.Ar +.Sh DESCRIPTION +The +.Nm lorder +utility uses +.Xr nm 1 +to determine interdependencies in the list of object files +specified on the command line. +.Nm Lorder +outputs a list of file names where the first file contains a symbol +which is defined by the second file. +.Pp +The output is normally used with +.Xr tsort 1 +when a library is created to determine the optimum ordering of the +object modules so that all references may be resolved in a single +pass of the loader. +.Sh EXAMPLES +.Bd -literal -offset indent +ar cr library.a `lorder ${OBJS} tsort` +.Ed +.Sh SEE ALSO +.Xr ar 1 , +.Xr ld 1 , +.Xr nm 1 , +.Xr ranlib 1 , +.Xr tsort 1 +.Sh HISTORY +An +.Nm lorder +utility appeared in +.At v7 . diff --git a/usr.bin/lorder/lorder.sh b/usr.bin/lorder/lorder.sh new file mode 100644 index 0000000..dea1e10 --- /dev/null +++ b/usr.bin/lorder/lorder.sh @@ -0,0 +1,89 @@ +#!/bin/sh - +# +# 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 the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)lorder.sh 8.1 (Berkeley) 6/6/93 +# + +PATH=/bin:/usr/bin +export PATH + +# only one argument is a special case, just output the name twice +case $# in + 0) + echo "usage: lorder file ..."; + exit ;; + 1) + echo $1 $1; + exit ;; +esac + +# temporary files +R=/tmp/_reference_$$ +S=/tmp/_symbol_$$ + +# remove temporary files on HUP, INT, QUIT, PIPE, TERM +trap "rm -f $R $S; exit 1" 1 2 3 13 15 + +# if the line ends in a colon, assume it's the first occurrence of a new +# object file. Echo it twice, just to make sure it gets into the output. +# +# if the line has " T " or " D " it's a globally defined symbol, put it +# into the symbol file. +# +# if the line has " U " it's a globally undefined symbol, put it into +# the reference file. +nm -go $* | sed " + /:$/ { + s/:// + s/.*/& &/ + p + d + } + / [TD] / { + s/:.* [TD] / / + w $S + d + } + / U / { + s/:.* U / / + w $R + } + d +" + +# sort symbols and references on the first field (the symbol) +# join on that field, and print out the file names. +sort +1 $R -o $R +sort +1 $S -o $S +join -j 2 -o 1.1 2.1 $R $S +rm -f $R $S diff --git a/usr.bin/m4/serv.c b/usr.bin/m4/serv.c new file mode 100644 index 0000000..54a2e59 --- /dev/null +++ b/usr.bin/m4/serv.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1989 + * The Regents of the University of California. All rights reserved. + * (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. + * + * This code is derived from software contributed to Berkeley by + * Ozan Yigit. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)serv.c 5.4 (Berkeley) 1/21/94"; +#endif /* not lint */ + +/* + * serv.c + * Facility: m4 macro processor + * by: oz + */ + +#include +#include +#include +#include "mdef.h" +#include "extr.h" +#include "pathnames.h" + +extern ndptr lookup(); +extern ndptr addent(); + +char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ + +/* + * expand - user-defined macro expansion + * + */ +expand(argv, argc) +register char *argv[]; +register int argc; +{ + register char *t; + register char *p; + register int n; + register int argno; + + t = argv[0]; /* defn string as a whole */ + p = t; + while (*p) + p++; + p--; /* last character of defn */ + while (p > t) { + if (*(p-1) != ARGFLAG) + putback(*p); + else { + switch (*p) { + + case '#': + pbnum(argc-2); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ((argno = *p - '0') < argc-1) + pbstr(argv[argno+1]); + break; + case '*': + for (n = argc - 1; n > 2; n--) { + pbstr(argv[n]); + putback(','); + } + pbstr(argv[2]); + break; + default : + putback(*p); + break; + } + p--; + } + p--; + } + if (p == t) /* do last character */ + putback(*p); +} + +/* + * dodefine - install definition in the table + * + */ +dodefine(name, defn) +register char *name; +register char *defn; +{ + register ndptr p; + + if (!*name) + error("m4: null definition."); + if (strcmp(name, defn) == 0) + error("m4: recursive definition."); + if ((p = lookup(name)) == nil) + p = addent(name); + else if (p->defn != null) + free(p->defn); + if (!*defn) + p->defn = null; + else + p->defn = strdup(defn); + p->type = MACRTYPE; +} + +/* + * dodefn - push back a quoted definition of + * the given name. + */ + +dodefn(name) +char *name; +{ + register ndptr p; + + if ((p = lookup(name)) != nil && p->defn != null) { + putback(rquote); + pbstr(p->defn); + putback(lquote); + } +} + +/* + * dopushdef - install a definition in the hash table + * without removing a previous definition. Since + * each new entry is entered in *front* of the + * hash bucket, it hides a previous definition from + * lookup. + */ +dopushdef(name, defn) +register char *name; +register char *defn; +{ + register ndptr p; + + if (!*name) + error("m4: null definition"); + if (strcmp(name, defn) == 0) + error("m4: recursive definition."); + p = addent(name); + if (!*defn) + p->defn = null; + else + p->defn = strdup(defn); + p->type = MACRTYPE; +} + +/* + * dodumpdef - dump the specified definitions in the hash + * table to stderr. If nothing is specified, the entire + * hash table is dumped. + * + */ +dodump(argv, argc) +register char *argv[]; +register int argc; +{ + register int n; + ndptr p; + + if (argc > 2) { + for (n = 2; n < argc; n++) + if ((p = lookup(argv[n])) != nil) + fprintf(stderr, dumpfmt, p->name, + p->defn); + } + else { + for (n = 0; n < HASHSIZE; n++) + for (p = hashtab[n]; p != nil; p = p->nxtptr) + fprintf(stderr, dumpfmt, p->name, + p->defn); + } +} + +/* + * doifelse - select one of two alternatives - loop. + * + */ +doifelse(argv,argc) +register char *argv[]; +register int argc; +{ + cycle { + if (strcmp(argv[2], argv[3]) == 0) + pbstr(argv[4]); + else if (argc == 6) + pbstr(argv[5]); + else if (argc > 6) { + argv += 3; + argc -= 3; + continue; + } + break; + } +} + +/* + * doinclude - include a given file. + * + */ +doincl(ifile) +char *ifile; +{ + if (ilevel+1 == MAXINP) + error("m4: too many include files."); + if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) { + ilevel++; + return (1); + } + else + return (0); +} + +#ifdef EXTENDED +/* + * dopaste - include a given file without any + * macro processing. + */ +dopaste(pfile) +char *pfile; +{ + FILE *pf; + register int c; + + if ((pf = fopen(pfile, "r")) != NULL) { + while((c = getc(pf)) != EOF) + putc(c, active); + (void) fclose(pf); + return(1); + } + else + return(0); +} +#endif + +/* + * dochq - change quote characters + * + */ +dochq(argv, argc) +register char *argv[]; +register int argc; +{ + if (argc > 2) { + if (*argv[2]) + lquote = *argv[2]; + if (argc > 3) { + if (*argv[3]) + rquote = *argv[3]; + } + else + rquote = lquote; + } + else { + lquote = LQUOTE; + rquote = RQUOTE; + } +} + +/* + * dochc - change comment characters + * + */ +dochc(argv, argc) +register char *argv[]; +register int argc; +{ + if (argc > 2) { + if (*argv[2]) + scommt = *argv[2]; + if (argc > 3) { + if (*argv[3]) + ecommt = *argv[3]; + } + else + ecommt = ECOMMT; + } + else { + scommt = SCOMMT; + ecommt = ECOMMT; + } +} + +/* + * dodivert - divert the output to a temporary file + * + */ +dodiv(n) +register int n; +{ + if (n < 0 || n >= MAXOUT) + n = 0; /* bitbucket */ + if (outfile[n] == NULL) { + m4temp[UNIQUE] = n + '0'; + if ((outfile[n] = fopen(m4temp, "w")) == NULL) + error("m4: cannot divert."); + } + oindex = n; + active = outfile[n]; +} + +/* + * doundivert - undivert a specified output, or all + * other outputs, in numerical order. + */ +doundiv(argv, argc) +register char *argv[]; +register int argc; +{ + register int ind; + register int n; + + if (argc > 2) { + for (ind = 2; ind < argc; ind++) { + n = atoi(argv[ind]); + if (n > 0 && n < MAXOUT && outfile[n] != NULL) + getdiv(n); + + } + } + else + for (n = 1; n < MAXOUT; n++) + if (outfile[n] != NULL) + getdiv(n); +} + +/* + * dosub - select substring + * + */ +dosub (argv, argc) +register char *argv[]; +register int argc; +{ + register char *ap, *fc, *k; + register int nc; + + if (argc < 5) + nc = MAXTOK; + else +#ifdef EXPR + nc = expr(argv[4]); +#else + nc = atoi(argv[4]); +#endif + ap = argv[2]; /* target string */ +#ifdef EXPR + fc = ap + expr(argv[3]); /* first char */ +#else + fc = ap + atoi(argv[3]); /* first char */ +#endif + if (fc >= ap && fc < ap+strlen(ap)) + for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--) + putback(*k); +} + +/* + * map: + * map every character of s1 that is specified in from + * into s3 and replace in s. (source s1 remains untouched) + * + * This is a standard implementation of map(s,from,to) function of ICON + * language. Within mapvec, we replace every character of "from" with + * the corresponding character in "to". If "to" is shorter than "from", + * than the corresponding entries are null, which means that those + * characters dissapear altogether. Furthermore, imagine + * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, + * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' + * ultimately maps to `*'. In order to achieve this effect in an efficient + * manner (i.e. without multiple passes over the destination string), we + * loop over mapvec, starting with the initial source character. if the + * character value (dch) in this location is different than the source + * character (sch), sch becomes dch, once again to index into mapvec, until + * the character value stabilizes (i.e. sch = dch, in other words + * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary + * character, it will stabilize, since mapvec[0] == 0 at all times. At the + * end, we restore mapvec* back to normal where mapvec[n] == n for + * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is + * about 5 times faster than any algorithm that makes multiple passes over + * destination string. + * + */ + +map(dest,src,from,to) +register char *dest; +register char *src; +register char *from; +register char *to; +{ + register char *tmp; + register char sch, dch; + static char mapvec[128] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127 + }; + + if (*src) { + tmp = from; + /* + * create a mapping between "from" and "to" + */ + while (*from) + mapvec[*from++] = (*to) ? *to++ : (char) 0; + + while (*src) { + sch = *src++; + dch = mapvec[sch]; + while (dch != sch) { + sch = dch; + dch = mapvec[sch]; + } + if (*dest = dch) + dest++; + } + /* + * restore all the changed characters + */ + while (*tmp) { + mapvec[*tmp] = *tmp; + tmp++; + } + } + *dest = (char) 0; +} diff --git a/usr.bin/mail/Makefile b/usr.bin/mail/Makefile new file mode 100644 index 0000000..576ce83 --- /dev/null +++ b/usr.bin/mail/Makefile @@ -0,0 +1,19 @@ +# @(#)Makefile 8.2 (Berkeley) 1/25/94 + +PROG= mail +CFLAGS+=-R -DUSE_OLD_TTY +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 + +beforeinstall: + cd ${.CURDIR}/misc; install -c -o ${BINOWN} -g ${BINGRP} \ + -m 444 ${SFILES} ${DESTDIR}/usr/share/misc + cd ${.CURDIR}/misc; install -c -o root -g wheel \ + -m 644 ${EFILES} ${DESTDIR}/etc + +.include diff --git a/usr.bin/mail/USD.doc/Makefile b/usr.bin/mail/USD.doc/Makefile new file mode 100644 index 0000000..b31b448 --- /dev/null +++ b/usr.bin/mail/USD.doc/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= usd/07.mail +SRCS= mail0.nr mail1.nr mail2.nr mail3.nr mail4.nr mail5.nr mail6.nr \ + mail7.nr mail8.nr mail9.nr maila.nr +MACROS= -me + +paper.ps: ${SRCS} + ${TBL} ${SRCS} | ${ROFF} > ${.TARGET} + +.include diff --git a/usr.bin/mail/USD.doc/mail0.nr b/usr.bin/mail/USD.doc/mail0.nr new file mode 100644 index 0000000..15955be --- /dev/null +++ b/usr.bin/mail/USD.doc/mail0.nr @@ -0,0 +1,71 @@ +.\" 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. +.\" +.\" @(#)mail0.nr 8.1 (Berkeley) 6/8/93 +.\" +.eh 'USD:7-%''Mail Reference Manual' +.oh 'Mail Reference Manual''USD:7-%' +.if n \ +.nr fs .5v +.\".he 'Mail Reference Manual'\n(mo/\n(dy/\n(yr'%' +.tp +.sp 1.0i +.sz 12 +.rb +.(l C +MAIL REFERENCE MANUAL +.)l +.sz 10 +.sp 2 +.i +.(l C +Kurt Shoens +.)l +.r +.(l C +Revised by +.)l +.(l C +.i +Craig Leres\ \c +.r +and\ \c +.i +Mark Andrews +.)l +.r +.(l C +Version 5.5 + + +\*(td +.)l +.pn 2 diff --git a/usr.bin/mail/USD.doc/mail1.nr b/usr.bin/mail/USD.doc/mail1.nr new file mode 100644 index 0000000..bbb920d --- /dev/null +++ b/usr.bin/mail/USD.doc/mail1.nr @@ -0,0 +1,92 @@ +.\" 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. +.\" +.\" @(#)mail1.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 Introduction +.pp +.i Mail +provides a simple and friendly environment for sending and receiving mail. +It divides incoming mail into +its constituent messages and allows the user to deal with them +in any order. In addition, it provides a set of +.i ed -\c +like commands for manipulating messages and sending mail. +.i Mail +offers the user simple editing capabilities to ease the composition +of outgoing messages, as well as providing the ability to define and send +to names which address groups of users. Finally, +.i Mail +is able to send and receive messages across such networks as the +ARPANET, UUCP, and Berkeley network. +.pp +This document describes how to use the +.i Mail +program to send and receive messages. The reader is not assumed to +be familiar with other message handling systems, but should be +familiar with the \s-2UNIX\s0\** +.(f +\** \s-1UNIX\s0 is a trademark of Bell Laboratories. +.)f +shell, the text editor, and some of the common \s-2UNIX\s0 commands. +.q "The \s-2UNIX\s0 Programmer's Manual," +.q "An Introduction to Csh," +and +.q "Text Editing with Ex and Vi" +can be consulted for more information on these topics. +.pp +Here is how messages are handled: +the mail system accepts incoming +.i messages +for you from other people +and collects them in a file, called your +.i "system mailbox" . +When you login, the system notifies you if there are any messages +waiting in your system mailbox. If you are a +.i csh +user, you will be notified when new mail arrives if you inform +the shell of the location of your mailbox. On version 7 systems, +your system mailbox is located in the directory /usr/spool/mail +in a file with your login name. If your login name is +.q sam, +then you can make +.i csh +notify you of new mail by including the following line in your .cshrc +file: +.(l +set mail=/usr/spool/mail/sam +.)l +When you read your mail using +.i Mail , +it reads your system mailbox and separates that file into the +individual messages that have been sent to you. You can then +read, reply to, delete, or save these messages. +Each message is marked with its author and the date they sent it. diff --git a/usr.bin/mail/USD.doc/mail2.nr b/usr.bin/mail/USD.doc/mail2.nr new file mode 100644 index 0000000..f64aaa6 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail2.nr @@ -0,0 +1,617 @@ +.\" 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. +.\" +.\" @(#)mail2.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Common usage" +.pp +The +.i Mail +command has two distinct usages, according to whether one +wants to send or receive mail. Sending mail is simple: to send a +message to a user whose login name is, say, +\*(lqroot,\*(rq +use the shell +command: +.(l +% Mail root +.)l +then type your message. When you reach the end of the message, type +an EOT (control\-d) at the beginning of a line, which will cause +.i Mail +to echo \*(lqEOT\*(rq and return you to the Shell. When the user you sent mail +to next logs in, he will receive the message: +.(l +You have mail. +.)l +to alert him to the existence of your message. +.pp +If, while you are composing the message +you decide that you do not wish to send it after all, you can +abort the letter with a \s-2RUBOUT\s0. Typing a single \s-2RUBOUT\s0 +causes +.i Mail +to print +.(l +(Interrupt -- one more to kill letter) +.)l +Typing a second +\s-2RUBOUT\s0 causes +.i Mail +to save your partial letter on the file +.q dead.letter +in your home directory and abort the letter. +Once you have +sent mail to someone, there is no way to undo the act, so be +careful. +.pp +The message your recipient reads will consist of the message you +typed, preceded by a line telling who sent the message (your login name) +and the date and time it +was sent. +.pp +If you want to send the same message to several other people, you can list +their login names on the command line. +Thus, +.(l +% Mail sam bob john +Tuition fees are due next Friday. Don't forget!! + +EOT +% +.)l +will send the reminder to sam, bob, and john. +.pp +If, when you log in, you see the message, +.(l +You have mail. +.)l +you can read the mail by typing simply: +.(l +% Mail +.)l +.i Mail +will respond by typing its version number and date and then listing +the messages you have waiting. Then it will type a prompt and await +your command. The messages are assigned numbers starting with 1 \*- you +refer to the messages with these numbers. +.i Mail +keeps track of which messages are +.i new +(have been sent since you last read your mail) and +.i read +(have been read by you). New messages have an +.b N +next to them in the header listing and old, but unread messages have +a +.b U +next to them. +.i Mail +keeps track of new/old and read/unread messages by putting a +header field called +.q Status +into your messages. +.pp +To look at a specific message, use the +.b type +command, which may be abbreviated to simply +.b t . +For example, if you had the following messages: +.(l +N 1 root Wed Sep 21 09:21 "Tuition fees" +N 2 sam Tue Sep 20 22:55 +.)l +you could examine the first message by giving the command: +.(l +type 1 +.)l +which might cause +.i Mail +to respond with, for example: +.(l +Message 1: +From root Wed Sep 21 09:21:45 1978 +Subject: Tuition fees +Status: R + +Tuition fees are due next Wednesday. Don't forget!! + +.)l +Many +.i Mail +commands that operate on messages take a message number as an +argument like the +.b type +command. For these commands, there is a notion of a current +message. When you enter the +.i Mail +program, the current message is initially the first one. Thus, +you can often omit the message number and use, for example, +.(l +t +.)l +to type the current message. As a further shorthand, you can type a message +by simply giving its message number. Hence, +.(l +1 +.)l +would type the first message. +.pp +Frequently, it is useful to read the messages in your mailbox in order, +one after another. You can read the next message in +.i Mail +by simply typing a newline. As a special case, you can type a newline +as your first command to +.i Mail +to type the first message. +.pp +If, after typing a message, you wish to immediately send a reply, +you can do so with the +.b reply +command. +.b Reply , +like +.b type , +takes a message number as an argument. +.i Mail +then begins a message addressed to the user who sent you the message. +You may then type in your letter in reply, followed by a +at the beginning of a line, as before. +.i Mail +will type EOT, then type the ampersand prompt to indicate its readiness +to accept another command. In our example, if, after typing the +first message, you wished to reply to it, you might give the command: +.(l +reply +.)l +.i Mail +responds by typing: +.(l +To: root +Subject: Re: Tuition fees +.)l +and waiting for you to enter your letter. +You are now in the message collection mode described at the beginning +of this section and +.i Mail +will gather up your message up to a control\-d. +Note that it copies the subject +header from the original message. This is useful in that correspondence +about a particular matter will tend to retain the same subject heading, +making it easy to recognize. If there are other header fields in +the message, the information found will also be used. +For example, if the letter had a +.q "To:" +header listing several recipients, +.i Mail +would arrange to send your replay to the same people as well. +Similarly, if the original message contained a +.q "Cc:" +(carbon copies to) field, +.i Mail +would send your reply to +.i those +users, too. +.i Mail +is careful, though, not too send the message to +.i you , +even if you appear in the +.q "To:" +or +.q "Cc:" +field, unless you ask to be included explicitly. See section 4 for more +details. +.pp +After typing in your letter, the dialog with +.i Mail +might look like the following: +.(l +reply +To: root +Subject: Tuition fees + +Thanks for the reminder +EOT +& +.)l +.pp +The +.b reply +command is especially useful for sustaining extended conversations +over the message system, with other +.q listening +users receiving copies of the conversation. The +.b reply +command can be abbreviated to +.b r . +.pp +Sometimes you will receive a message that has been sent to +several people and wish to reply +.i only +to the person who sent it. +.b Reply +with a capital +.b R +replies to a message, but sends a copy to the sender only. +.pp +If you wish, while reading your mail, to send a message to someone, +but not as a reply to one of your messages, you can send the message +directly with the +.b mail +command, which takes as arguments the names of the recipients you wish +to send to. For example, to send a message to +.q frank, +you would do: +.(l +mail frank +This is to confirm our meeting next Friday at 4. +EOT +& +.)l +The +.b mail +command can be abbreviated to +.b m . +.pp +Normally, each message you receive is saved in the file +.i mbox +in your login directory at the time you leave +.i Mail . +Often, +however, you will not want to save a particular message you +have received because it is only of passing interest. To avoid +saving a message in +.i mbox +you can delete it using the +.b delete +command. In our example, +.(l +delete 1 +.)l +will prevent +.i Mail +from saving message 1 (from root) in +.i mbox . +In addition to not saving deleted messages, +.i Mail +will not let +you type them, either. The effect is to make the message disappear +altogether, along with its number. The +.b delete +command can be abbreviated to simply +.b d . +.pp +Many features of +.i Mail +can be tailored to your liking with the +.b set +command. The +.b set +command has two forms, depending on whether you are setting +a +.i binary +option or a +.i valued +option. +Binary options are either on or off. For example, the +.q ask +option informs +.i Mail +that each time you send a message, you want it to prompt you for +a subject header, to be included in the message. +To set the +.q ask +option, you would type +.(l +set ask +.)l +.pp +Another useful +.i Mail +option is +.q hold. +Unless told otherwise, +.i Mail +moves the messages from your system mailbox to the file +.i mbox +in your home directory when you leave +.i Mail . +If you want +.i Mail +to keep your letters in the system mailbox instead, you can set the +.q hold +option. +.pp +Valued options are values which +.i Mail +uses to adapt to your tastes. For example, the +.q SHELL +option tells +.i Mail +which shell you like to use, and is specified by +.(l +set SHELL=/bin/csh +.)l +for example. Note that no spaces are allowed in +.q "SHELL=/bin/csh." +A complete list of the +.i Mail +options appears in section 5. +.pp +Another important valued option is +.q crt. +If you use a fast video terminal, you will find that when you +print long messages, they fly by too quickly for you to read them. +With the +.q crt +option, you can make +.i Mail +print any message larger than a given number of lines by sending +it through a paging program. This program is specified by the +valued option \fBPAGER\fP. +If \fBPAGER\fP is not set, a default paginator is used. +For example, most CRT users with 24-line screens should do: +.(l +set crt=24 +.)l +to paginate messages that will not fit on their screens. +In the default state, \fImore\fP (default paginator) prints a screenful of +information, then types --More--. Type a space to see the next screenful. +.pp +Another adaptation to user needs that +.i Mail +provides is that of +.i aliases . +An alias is simply a name which stands for one or more +real user names. +.i Mail +sent to an alias is really sent to the list of real users +associated with it. For example, an alias can be defined for the +members of a project, so that you can send mail to the whole project +by sending mail to just a single name. The +.b alias +command in +.i Mail +defines an alias. Suppose that the users in a project are +named Sam, Sally, Steve, and Susan. To define an alias called +.q project +for them, you would use the +.i Mail +command: +.(l +alias project sam sally steve susan +.)l +The +.b alias +command can also be used to provide a convenient name for someone +whose user name is inconvenient. For example, if a user named +.q "Bob Anderson" +had the login name +.q anderson," +you might want to use: +.(l +alias bob anderson +.)l +so that you could send mail to the shorter name, +.q bob. +.pp +While the +.b alias +and +.b set +commands allow you to customize +.i Mail , +they have the drawback that they must be retyped each time you enter +.i Mail . +To make them more convenient to use, +.i Mail +always looks for two files when it is invoked. It first reads +a system wide file +.q /usr/lib/Mail.rc, +then a user specific file, +.q .mailrc, +which is found in the user's home directory. +The system wide file +is maintained by the system administrator and +contains +.b set +commands that are applicable to all users of the system. +The +.q .mailrc +file is usually used by each user to set options the way he likes +and define individual aliases. +For example, my .mailrc file looks like this: +.(l +set ask nosave SHELL=/bin/csh +.)l +As you can see, it is possible to set many options in the +same +.b set +command. The +.q nosave +option is described in section 5. +.pp +Mail aliasing is implemented +at the system-wide level +by the mail delivery +system +.i sendmail . +These aliases are stored in the file /usr/lib/aliases and are +accessible to all users of the system. +The lines in /usr/lib/aliases are of +the form: +.(l +alias: name\*<1\*>, name\*<2\*>, name\*<3\*> +.)l +where +.i alias +is the mailing list name and the +.i name\* +are the members of the list. Long lists can be continued onto the next +line by starting the next line with a space or tab. Remember that you +must execute the shell command +.i newaliases +after editing /usr/lib/aliases since the delivery system +uses an indexed file created by +.i newaliases . +.pp +We have seen that +.i Mail +can be invoked with command line arguments which are people +to send the message to, or with no arguments to read mail. +Specifying the +.rb \-f +flag on the command line causes +.i Mail +to read messages from a file other than your system mailbox. +For example, if you have a collection of messages in +the file +.q letters +you can use +.i Mail +to read them with: +.(l +% Mail \-f letters +.)l +You can use all +the +.i Mail +commands described in this document to examine, modify, or delete +messages from your +.q letters +file, which will be rewritten when you leave +.i Mail +with the +.b quit +command described below. +.pp +Since mail that you read is saved in the file +.i mbox +in your home directory by default, you can read +.i mbox +in your home directory by using simply +.(l +% Mail \-f +.)l +.pp +Normally, messages that you examine using the +.b type +command are saved in the file +.q mbox +in your home directory if you leave +.i Mail +with the +.b quit +command described below. +If you wish to retain a message in your system mailbox +you can use the +.b preserve +command to tell +.i Mail +to leave it there. +The +.b preserve +command accepts a list of message numbers, just like +.b type +and may be abbreviated to +.b pre . +.pp +Messages in your system mailbox that you do not examine are +normally retained in your system mailbox automatically. +If you wish to have such a message saved in +.i mbox +without reading it, you may use the +.b mbox +command to have them so saved. For example, +.(l +mbox 2 +.)l +in our example would cause the second message (from sam) +to be saved in +.i mbox +when the +.b quit +command is executed. +.b Mbox +is also the way to direct messages to your +.i mbox +file if you have set the +.q hold +option described above. +.b Mbox +can be abbreviated to +.b mb . +.pp +When you have perused all the messages of interest, you can leave +.i Mail +with the +.b quit +command, which saves the messages you have typed but not +deleted in the file +.i mbox +in your login directory. Deleted messages are discarded irretrievably, +and messages left untouched are preserved in your system mailbox so +that you will see them the next time you type: +.(l +% Mail +.)l +The +.b quit +command can be abbreviated to simply +.b q . +.pp +If you wish for some reason to leave +.i Mail +quickly without altering either your system mailbox or +.i mbox , +you can type the +.b x +command (short for +.b exit ), +which will immediately return you to the Shell without changing anything. +.pp +If, instead, you want to execute a Shell command without leaving +.i Mail , +you +can type the command preceded by an exclamation point, just as in the +text editor. Thus, for instance: +.(l +!date +.)l +will print the current date without leaving +.i Mail . +.pp +Finally, the +.b help +command is available to print out a brief summary of the +.i Mail +commands, using only the single character command abbreviations. diff --git a/usr.bin/mail/USD.doc/mail3.nr b/usr.bin/mail/USD.doc/mail3.nr new file mode 100644 index 0000000..64f7634 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail3.nr @@ -0,0 +1,133 @@ +.\" 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. +.\" +.\" @(#)mail3.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Maintaining folders" +.pp +.i Mail +includes a simple facility for maintaining groups of messages together +in folders. This section describes this facility. +.pp +To use the folder facility, you must tell +.i Mail +where you wish to keep your folders. Each folder of messages will +be a single file. For convenience, all of your folders are kept in +a single directory of your choosing. To tell +.i Mail +where your folder directory is, put a line of the form +.(l +set folder=letters +.)l +in your +.i .mailrc +file. If, as in the example above, your folder directory does not +begin with a `/,' +.i Mail +will assume that your folder directory is to be found starting from +your home directory. Thus, if your home directory is +.b /usr/person +the above example told +.i Mail +to find your folder directory in +.b /usr/person/letters . +.pp +Anywhere a file name is expected, you can use a folder name, preceded +with `+.' For example, to put a message into a folder with the +.b save +command, you can use: +.(l +save +classwork +.)l +to save the current message in the +.i classwork +folder. If the +.i classwork +folder does not yet exist, it will be created. Note that messages +which are saved with the +.b save +command are automatically removed from your system mailbox. +.pp +In order to make a copy of a message in a folder without causing +that message to be removed from your system mailbox, use the +.b copy +command, which is identical in all other respects to the +.b save +command. For example, +.(l +copy +classwork +.)l +copies the current message into the +.i classwork +folder and leaves a copy in your system mailbox. +.pp +The +.b folder +command +can be used to direct +.i Mail +to the contents of a different folder. +For example, +.(l +folder +classwork +.)l +directs +.i Mail +to read the contents of the +.i classwork +folder. All of the commands that you can use on your system +mailbox are also applicable to folders, including +.b type , +.b delete , +and +.b reply . +To inquire which folder you are currently editing, use simply: +.(l +folder +.)l +.pp +To list your current set of folders, use the +.b folders +command. +.pp +To start +.i Mail +reading one of your folders, you can use the +.b \-f +option described in section 2. For example: +.(l +% Mail \-f +classwork +.)l +will cause +.i Mail +to read your +.i classwork +folder without looking at your system mailbox. diff --git a/usr.bin/mail/USD.doc/mail4.nr b/usr.bin/mail/USD.doc/mail4.nr new file mode 100644 index 0000000..b67bf03 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail4.nr @@ -0,0 +1,437 @@ +.\" 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. +.\" +.\" @(#)mail4.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "More about sending mail" +.sh 2 "Tilde escapes" +.pp +While typing in a message to be sent to others, it is often +useful to be able to invoke the text editor on the partial message, +print the message, execute a shell command, or do some other +auxiliary function. +.i Mail +provides these capabilities through +.i "tilde escapes" , +which consist of a tilde (~) at the beginning of a line, followed by +a single character which indicates the function to be performed. For +example, to print the text of the message so far, use: +.(l +~p +.)l +which will print a line of dashes, the recipients of your message, and +the text of the message so far. +Since +.i Mail +requires two consecutive \s-2RUBOUT\s0's to abort a letter, you +can use a single \s-2RUBOUT\s0 to abort the output of ~p or any other +~ escape without killing your letter. +.pp +If you are dissatisfied with the message as +it stands, you can invoke the text editor on it using the escape +.(l +~e +.)l +which causes the message to be copied into a temporary file and an +instance of the editor to be spawned. After modifying the message to +your satisfaction, write it out and quit the editor. +.i Mail +will respond +by typing +.(l +(continue) +.)l +after which you may continue typing text which will be appended to your +message, or type to end the message. +A standard text editor is provided by +.i Mail . +You can override this default by setting the valued option +.q EDITOR +to something else. For example, you might prefer: +.(l +set EDITOR=/usr/ucb/ex +.)l +.pp +Many systems offer a screen editor as an alternative to the standard +text editor, such as the +.i vi +editor from UC Berkeley. +To use the screen, or +.i visual +editor, on your current message, you can use the escape, +.(l +~v +.)l +~v works like ~e, except that the screen editor is invoked instead. +A default screen editor is defined by +.i Mail . +If it does not suit you, you can set the valued option +.q VISUAL +to the path name of a different editor. +.pp +It is often useful to be able to include the contents of some +file in your message; the escape +.(l +~r filename +.)l +is provided for this purpose, and causes the named file to be appended +to your current message. +.i Mail +complains if the file doesn't exist +or can't be read. If the read is successful, the number of lines and +characters appended to your message is printed, after which you may continue +appending text. The filename may contain shell metacharacters like * and ? +which are expanded according to the conventions of your shell. +.pp +As a special case of ~r, the escape +.(l +~d +.)l +reads in the file +.q dead.letter +in your home directory. This is often useful since +.i Mail +copies the text +of your message there when you abort a message with \s-2RUBOUT\s0. +.pp +To save the current text of your message on a file you may use the +.(l +~w filename +.)l +escape. +.i Mail +will print out the number of lines and characters written +to the file, after which you may continue appending text to your message. +Shell metacharacters may be used in the filename, as in ~r and are expanded +with the conventions of your shell. +.pp +If you are sending mail from within +.i Mail's +command mode +you can read a message sent to you into the message +you are constructing with the escape: +.(l +~m 4 +.)l +which will read message 4 into the current message, shifted right by +one tab stop. You can name any non-deleted message, or list of messages. +Messages can also be forwarded without shifting by a tab stop with ~f. +This is the usual way to forward a message. +.pp +If, in the process of composing a message, you decide to add additional +people to the list of message recipients, you can do so with the escape +.(l +~t name1 name2 ... +.)l +You may name as few or many additional recipients as you wish. Note +that the users originally on the recipient list will still receive +the message; you cannot remove someone from the recipient +list with ~t. +.pp +If you wish, you can associate a subject with your message by using the +escape +.(l +~s Arbitrary string of text +.)l +which replaces any previous subject with +.q "Arbitrary string of text." +The subject, if given, is sent near the +top of the message prefixed with +.q "Subject:" +You can see what the message will look like by using ~p. +.pp +For political reasons, one occasionally prefers to list certain +people as recipients of carbon copies of a message rather than +direct recipients. The escape +.(l +~c name1 name2 ... +.)l +adds the named people to the +.q "Cc:" +list, similar to ~t. +Again, you can execute ~p to see what the message will look like. +.pp +The escape +.(l +~b name1 name2 ... +.)l +adds the named people to the +.q "Cc:" +list, but does not make the names visible in the +.q "Cc:" +line ("blind" carbon copy). +.pp +The recipients of the message together constitute the +.q "To:" +field, the subject the +.q "Subject:" +field, and the carbon copies the +.q "Cc:" +field. If you wish to edit these in ways impossible with the ~t, ~s, ~c +and ~b escapes, you can use the escape +.(l +~h +.)l +which prints +.q "To:" +followed by the current list of recipients and leaves the cursor +(or printhead) at the end of the line. If you type in ordinary +characters, they are appended to the end of the current list of +recipients. You can also use your erase character to erase back into +the list of recipients, or your kill character to erase them altogether. +Thus, for example, if your erase and kill characters are the standard +(on printing terminals) # and @ symbols, +.(l +~h +To: root kurt####bill +.)l +would change the initial recipients +.q "root kurt" +to +.q "root bill." +When you type a newline, +.i Mail +advances to the +.q "Subject:" +field, where the same rules apply. Another newline brings you to +the +.q "Cc:" +field, which may be edited in the same fashion. Another newline +brings you to the +.q "Bcc:" +("blind" carbon copy) field, which follows the same rules as the "Cc:" +field. Another newline +leaves you appending text to the end of your message. You can use +~p to print the current text of the header fields and the body +of the message. +.pp +To effect a temporary escape to the shell, the escape +.(l +~!command +.)l +is used, which executes +.i command +and returns you to mailing mode without altering the text of +your message. If you wish, instead, to filter the body of your +message through a shell command, then you can use +.(l +~|command +.)l +which pipes your message through the command and uses the output +as the new text of your message. If the command produces no output, +.i Mail +assumes that something is amiss and retains the old version +of your message. A frequently-used filter is the command +.i fmt , +designed to format outgoing mail. +.pp +To effect a temporary escape to +.i Mail +command mode instead, you can use the +.(l +~:\fIMail command\fP +.)l +escape. This is especially useful for retyping the message you are +replying to, using, for example: +.(l +~:t +.)l +It is also useful for setting options and modifying aliases. +.pp +If you wish abort the current message, you can use the escape +.(l +~q +.)l +This will terminate the current message and return you to the +shell (or \fIMail\fP if you were using the \fBmail\fP command). +If the \fBsave\fP option is set, the message will be copied +to the file +.q dead.letter +in your home directory. +.pp +If you wish (for some reason) to send a message that contains +a line beginning with a tilde, you must double it. Thus, for example, +.(l +~~This line begins with a tilde. +.)l +sends the line +.(l +~This line begins with a tilde. +.)l +.pp +Finally, the escape +.(l +~? +.)l +prints out a brief summary of the available tilde escapes. +.pp +On some terminals (particularly ones with no lower case) +tilde's are difficult to type. +.i Mail +allows you to change the escape character with the +.q escape +option. For example, I set +.(l +set escape=] +.)l +and use a right bracket instead of a tilde. If I ever need to +send a line beginning with right bracket, I double it, just as for ~. +Changing the escape character removes the special meaning of ~. +.sh 2 "Network access" +.pp +This section describes how to send mail to people on other machines. +Recall that sending to a plain login name sends mail to that person +on your machine. If your machine is directly (or sometimes, even, +indirectly) connected to the Arpanet, you can send messages to people +on the Arpanet using a name of the form +.(l +name@host.domain +.)l +where +.i name +is the login name of the person you're trying to reach, +.i host +is the name of the machine on the Arpanet, +and +.i domain +is the higher-level scope within which the hostname is known, e.g. EDU (for educational +institutions), COM (for commercial entities), GOV (for governmental agencies), +ARPA for many other things, BITNET or CSNET for those networks. +.pp +If your recipient logs in on a machine connected to yours by +UUCP (the Bell Laboratories supplied network that communicates +over telephone lines), sending mail can be a bit more complicated. +You must know the list of machines through which your message must +travel to arrive at his site. So, if his machine is directly connected +to yours, you can send mail to him using the syntax: +.(l +host!name +.)l +where, again, +.i host +is the name of the machine and +.i name +is the login name. +If your message must go through an intermediary machine first, you +must use the syntax: +.(l +intermediary!host!name +.)l +and so on. It is actually a feature of UUCP that the map of all +the systems in the network is not known anywhere (except where people +decide to write it down for convenience). Talk to your system administrator +about good ways to get places; the +.i uuname +command will tell you systems whose names are recognized, but not which +ones are frequently called or well-connected. +.pp +When you use the +.b reply +command to respond to a letter, there is a problem of figuring out the +names of the users in the +.q "To:" +and +.q "Cc:" +lists +.i "relative to the current machine" . +If the original letter was sent to you by someone on the local machine, +then this problem does not exist, but if the message came from a remote +machine, the problem must be dealt with. +.i Mail +uses a heuristic to build the correct name for each user relative +to the local machine. So, when you +.b reply +to remote mail, the names in the +.q "To:" +and +.q "Cc:" +lists may change somewhat. +.sh 2 "Special recipients" +.pp +As described previously, you can send mail to either user names or +.b alias +names. It is also possible to send messages directly to files or to +programs, using special conventions. If a recipient name has a +`/' in it or begins with a `+', it is assumed to be the +path name of a file into which +to send the message. If the file already exists, the message is +appended to the end of the file. If you want to name a file in +your current directory (ie, one for which a `/' would not usually +be needed) you can precede the name with `./' +So, to send mail to the file +.q memo +in the current directory, you can give the command: +.(l +% Mail ./memo +.)l +If the name begins with a `+,' it is expanded into the full path name +of the folder name in your folder directory. +This ability to send mail to files can be used for a variety of +purposes, such as maintaining a journal and keeping a record of +mail sent to a certain group of users. The second example can be +done automatically by including the full pathname of the record +file in the +.b alias +command for the group. Using our previous +.b alias +example, you might give the command: +.(l +alias project sam sally steve susan /usr/project/mail_record +.)l +Then, all mail sent to "project" would be saved on the file +.q /usr/project/mail_record +as well as being sent to the members of the project. This file +can be examined using +.i "Mail \-f" . +.pp +It is sometimes useful to send mail directly to a program, for +example one might write a project billboard program and want to access +it using +.i Mail . +To send messages to the billboard program, one can send mail +to the special name `|billboard' for example. +.i Mail +treats recipient names that begin with a `|' as a program to send +the mail to. An +.b alias +can be set up to reference a `|' prefaced name if desired. +.i Caveats : +the shell treats `|' specially, so it must be quoted on the command +line. Also, the `| program' must be presented as a single argument to +mail. The safest course is to surround the entire name with double +quotes. This also applies to usage in the +.b alias +command. For example, if we wanted to alias `rmsgs' to `rmsgs \-s' +we would need to say: +.(l +alias rmsgs "| rmsgs -s" +.)l diff --git a/usr.bin/mail/USD.doc/mail5.nr b/usr.bin/mail/USD.doc/mail5.nr new file mode 100644 index 0000000..b70ce95 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail5.nr @@ -0,0 +1,1041 @@ +.\" 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. +.\" +.\" @(#)mail5.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Additional features" +.pp +This section describes some additional commands useful for +reading your mail, setting options, and handling lists of messages. +.sh 2 "Message lists" +.pp +Several +.i Mail +commands accept a list of messages as an argument. +Along with +.b type +and +.b delete , +described in section 2, +there is the +.b from +command, which prints the message headers associated with the +message list passed to it. +The +.b from +command is particularly useful in conjunction with some of the +message list features described below. +.pp +A +.i "message list" +consists of a list of message numbers, ranges, and names, +separated by spaces or tabs. Message numbers may be either +decimal numbers, which directly specify messages, or one of the +special characters +.q \(ua +.q "." +or +.q "$" +to specify the first relevant, current, or last +relevant message, respectively. +.i Relevant +here means, for most commands +.q "not deleted" +and +.q "deleted" +for the +.b undelete +command. +.pp +A range of messages consists of two message numbers (of the form +described in the previous paragraph) separated by a dash. +Thus, to print the first four messages, use +.(l +type 1\-4 +.)l +and to print all the messages from the current message to the last +message, use +.(l +type .\-$ +.)l +.pp +A +.i name +is a user name. The user names given in the message list are +collected together and each message selected by other means +is checked to make sure it was sent by one of the named users. +If the message consists entirely of user names, then every +message sent by one of those users that is +.i relevant +(in the sense described earlier) +is selected. Thus, to print every message sent to you by +.q root, +do +.(l +type root +.)l +.pp +As a shorthand notation, you can specify simply +.q * +to get every +.i relevant +(same sense) +message. Thus, +.(l +type * +.)l +prints all undeleted messages, +.(l +delete * +.)l +deletes all undeleted messages, and +.(l +undelete * +.)l +undeletes all deleted messages. +.pp +You can search for the presence of a word in subject lines with +.b / . +For example, to print the headers of all messages that contain the +word +.q PASCAL, +do: +.(l +from /pascal +.)l +Note that subject searching ignores upper/lower case differences. +.sh 2 "List of commands" +.pp +This section describes all the +.i Mail +commands available when +receiving mail. +.ip "\fB\-\fP\ \ " +The +.rb \- +command goes to the previous message and prints it. The +.rb \- +command may be given a decimal number +.i n +as an argument, in which case the +.i n th +previous message is gone to and printed. +.ip "\fB?\fP\ \ " +Prints a brief summary of commands. +.ip "\fB!\fP\ \ " +Used to preface a command to be executed by the shell. +.ip "\fBPrint\fP\ \ " +Like +.b print , +but also print out ignored header fields. See also +\fBprint\fP, \fBignore\fP and \fBretain\fP. +\fBPrint\fP can be abbreviated to \fBP\fP. +.ip "\fBReply\fP or \fBRespond\fP\ \ " +Note the capital \fBR\fP in the name. +Frame a reply to a one or more messages. +The reply (or replies if you are using this on multiple messages) +will be sent ONLY to the person who sent you the message +(respectively, the set of people who sent the messages you are +replying to). +You can +add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP +tilde escapes. The subject in your reply is formed by prefacing the +subject in the original message with +.q "Re:" +unless it already began thus. +If the original message included a +.q "reply-to" +header field, the reply will go +.i only +to the recipient named by +.q "reply-to." +You type in your message using the same conventions available to you +through the +.b mail +command. +The +.b Reply +command is especially useful for replying to messages that were sent +to enormous distribution groups when you really just want to +send a message to the originator. Use it often. +\fBReply\fP (and \fBRespond\fP) can be abbreviated to \fBR\fP. +.ip "\fBType\fP\ \ " +Identical to the +.b Print +command. +\fBType\fP can be abbreviated to \fBT\fP. +.ip "\fBalias\fP\ \ " +Define a name to stand for a set of other names. +This is used when you want to send messages to a certain +group of people and want to avoid retyping their names. +For example +.(l +alias project john sue willie kathryn +.)l +creates an alias +.i project +which expands to the four people John, Sue, Willie, and Kathryn. +If no arguments are given, all currently-defined aliases are printed. +If one argument is given, that alias is printed (if it exists). +\fBAlias\fP can be abbreviated to \fBa\fP. +.ip "\fBalternates\fP\ \ " +If you have accounts on several machines, you may find it convenient +to use the /usr/lib/aliases on all the machines except one to direct +your mail to a single account. +The +.b alternates +command is used to inform +.i Mail +that each of these other addresses is really +.i you . +.i Alternates +takes a list of user names and remembers that they are all actually you. +When you +.b reply +to messages that were sent to one of these alternate names, +.i Mail +will not bother to send a copy of the message to this other address (which +would simply be directed back to you by the alias mechanism). +If +.i alternates +is given no argument, it lists the current set of alternate names. +.b Alternates +is usually used in the .mailrc file. +\fBAlternates\fP can be abbreviated to \fBalt\fP. +.ip "\fBchdir\fP\ \ " +The +.b chdir +command allows you to change your current directory. +.b Chdir +takes a single argument, which is taken to be the pathname of +the directory to change to. If no argument is given, +.b chdir +changes to your home directory. +\fBChdir\fP can be abbreviated to \fBc\fP. +.ip "\fBcopy\fP\ \ " +The +.b copy +command does the same thing that +.b save +does, except that it does not mark the messages it is used on +for deletion when you quit. +\fBCopy\fP can be abbreviated to \fBco\fP. +.ip "\fBdelete\fP\ \ " +Deletes a list of messages. Deleted messages can be reclaimed +with the +.b undelete +command. +\fBDelete\fP can be abbreviated to \fBd\fP. +.ip "\fBdp\fP or \fBdt\fP\ \ " +These +commands delete the current message and print the next message. +They are useful for quickly reading and disposing of mail. +If there is no next message, \fImail\fP says ``at EOF.'' +.ip "\fBedit\fP\ \ " +To edit individual messages using the text editor, the +.b edit +command is provided. The +.b edit +command takes a list of messages as described under the +.b type +command and processes each by writing it into the file +Message\c +.i x +where +.i x +is the message number being edited and executing the text editor on it. +When you have edited the message to your satisfaction, write the message +out and quit, upon which +.i Mail +will read the message back and remove the file. +.b Edit +can be abbreviated to +.b e . +.ip "\fBelse\fP\ \ " +Marks the end of the then-part of an +.b if +statement and the beginning of the +part to take effect if the condition of the +.b if +statement is false. +.ip "\fBendif\fP\ \ " +Marks the end of an +.b if +statement. +.ip "\fBexit\fP or \fBxit\fP\ \ " +Leave +.i Mail +without updating the system mailbox or the file your were reading. +Thus, if you accidentally delete several messages, you can use +.b exit +to avoid scrambling your mailbox. +\fBExit\fP can be abbreviated to \fBex\fP or \fBx\fP. +.ip "\fBfile\fP\ \ " +The same as +.b folder . +\fBFile\fP can be abbreviated to \fBfi\fP. +.ip "\fBfolders\fP\ \ " +List the names of the folders in your folder directory. +.ip "\fBfolder\fP\ \ " +The +.b folder +command switches to a new mail file or folder. With no arguments, it +tells you which file you are currently reading. If you give +it an argument, it will write out changes (such as deletions) +you have made in the current file and read the new file. +Some special conventions are recognized for the name: +.(b +.TS +center; +c c +l a. +Name Meaning +_ +# Previous file read +% Your system mailbox +%name \fIName\fP's system mailbox +& Your ~/mbox file ++folder A file in your folder directory +.TE +.)b +\fBFolder\fP can be abbreviated to \fBfo\fP. +.ip "\fBfrom\fP\ \ " +The +.b from +command takes a list of messages and prints out the header lines for each one; +hence +.(l +from joe +.)l +is the easy way to display all the message headers from \*(lqjoe.\*(rq +\fBFrom\fP can be abbreviated to \fBf\fP. +.ip "\fBheaders\fP\ \ " +When you start up +.i Mail +to read your mail, it lists the message headers that you have. +These headers tell you who each message is from, when they were +received, how many lines and characters each message is, and the +.q "Subject:" +header field of each message, if present. In addition, +.i Mail +tags the message header of each message that has been the object +of the +.b preserve +command with a +.q P. +Messages that have been +.b saved +or +.b written +are flagged with a +.q *. +Finally, +.b deleted +messages are not printed at all. If you wish to reprint the current +list of message headers, you can do so with the +.b headers +command. The +.b headers +command (and thus the initial header listing) +only lists the first so many message headers. +The number of headers listed depends on the speed of your +terminal. +This can be overridden by specifying the number of headers you +want with the +.i window +option. +.i Mail +maintains a notion of the current +.q window +into your messages for the purposes of printing headers. +Use the +.b z +command to move forward and back a window. +You can move +.i Mail's +notion of the current window directly to a particular message by +using, for example, +.(l +headers 40 +.)l +to move +.i Mail's +attention to the messages around message 40. +If a ``+'' argument is given, then the next screenful of message headers is +printed, and if a ``\-'' argument is given, the previous screenful of message +headers is printed. +\fBHeaders\fP can be abbreviated to \fBh\fP. +.ip "\fBhelp\fP\ \ " +Print a brief and usually out of date help message about the commands +in +.i Mail . +The +.i man +page for +.i mail +is usually more up-to-date than either the help message or this manual. +It is also a synonym for \fB?\fP. +.ip "\fBhold\fP\ \ " +Arrange to hold a list of messages in the system mailbox, instead +of moving them to the file +.i mbox +in your home directory. If you set the binary option +.i hold , +this will happen by default. +It does not override the \fBdelete\fP command. +\fBHold\fP can be abbreviated to \fBho\fP. +.ip "\fBif\fP\ \ " +Commands in your +.q .mailrc +file can be executed conditionally depending on whether you are +sending or receiving mail with the +.b if +command. For example, you can do: +.(l +if receive + \fIcommands\fP... +endif +.)l +An +.b else +form is also available: +.(l +if send + \fIcommands\fP... +else + \fIcommands\fP... +endif +.)l +Note that the only allowed conditions are +.b receive +and +.b send . +.ip "\fBignore\fP \ \ " +.b N.B.: +.i Ignore +has been superseded by +.i retain. +.br +Add the list of header fields named to the +.i "ignore list" . +Header fields in the ignore list are not printed on your +terminal when you print a message. This allows you to suppress +printing of certain machine-generated header fields, such as +.i Via +which are not usually of interest. The +.b Type +and +.b Print +commands can be used to print a message in its entirety, including +ignored fields. +If +.b ignore +is executed with no arguments, it lists the current set of ignored fields. +.ip "\fBlist\fP\ \ " +List the valid +.i Mail +commands. +\fBList\fP can be abbreviated to \fBl\fP. +.. .ip \fBlocal\fP +.. Define a list of local names for this host. This command is useful +.. when the host is known by more than one name. Names in the list +.. may be qualified be the domain of the host. The first name on the local +.. list is the +.. .i distinguished +.. name of the host. +.. The names on the local list are used by +.. .i Mail +.. to decide which addresses are local to the host. +.. For example: +.. .(l +.. local ucbarpa.BERKELEY.ARPA arpa.BERKELEY.ARPA \\ +.. arpavax.BERKELEY.ARPA r.BERKELEY.ARPA \\ +.. ucb-arpa.ARPA +.. .)l +.. From this list we see that +.. .i "fred@ucbarpa.BERKELEY.ARPA", +.. .i "harold@arpa.BERKELEY", +.. and +.. .i "larry@r" +.. are all addresses of users on the local host. +.. The +.. .b local +.. command is usually not used be general users since it is designed for +.. local configuration; it is usually found in the file /usr/lib/Mail.rc. +.ip "\fBmail\fP\ \ " +Send mail to one or more people. If you have the +.i ask +option set, +.i Mail +will prompt you for a subject to your message. Then you +can type in your message, using tilde escapes as described in +section 4 to edit, print, or modify your message. To signal your +satisfaction with the message and send it, type control-d at the +beginning of a line, or a . alone on a line if you set the option +.i dot . +To abort the message, type two interrupt characters (\s-2RUBOUT\s0 +by default) in a row or use the +.b ~q +escape. +The \fBmail\fP command can be abbreviated to \fBm\fP. +.ip "\fBmbox\fP\ \ " +Indicate that a list of messages be sent to +.i mbox +in your home directory when you quit. This is the default +action for messages if you do +.i not +have the +.i hold +option set. +.ip "\fBnext\fP or \fB+\fP\ \ " +The +.b next +command goes to the next message and types it. If given a message list, +.b next +goes to the first such message and types it. Thus, +.(l +next root +.)l +goes to the next message sent by +.q root +and types it. The +.b next +command can be abbreviated to simply a newline, which means that one +can go to and type a message by simply giving its message number or +one of the magic characters +.q "^" +.q "." +or +.q "$". +Thus, +.(l +\&. +.)l +prints the current message and +.(l +4 +.)l +prints message 4, as described previously. +\fBNext\fP can be abbreviated to \fBn\fP. +.ip "\fBpreserve\fP\ \ " +Same as +.b hold . +Cause a list of messages to be held in your system mailbox when you quit. +\fBPreserve\fP can be abbreviated to \fBpre\fP. +.ip "\fBprint\fP\ \ " +Print the specified messages. If the +.b crt +variable is set, messages longer than the number of lines it indicates +are paged through the command specified by the \fBPAGER\fP variable. +The \fBprint\fP command can be abbreviated to \fBp\fP. +.ip "\fBquit\fP\ \ " +Terminates the session, saving all undeleted, unsaved and unwritten messages +in the user's \fImbox\fP file in their login directory +(messages marked as having been read), preserving all +messages marked with \fBhold\fP or \fBpreserve\fP or never referenced +in their system mailbox. +Any messages that were deleted, saved, written or saved to \fImbox\fP are +removed from their system mailbox. +If new mail has arrived during the session, the message +``You have new mail'' is given. If given while editing a mailbox file +with the \fB\-f\fP flag, then the edit file is rewritten. +A return to the Shell is effected, unless the rewrite of edit file fails, +in which case the user can escape with the \fBexit\fP command. +\fBQuit\fP can be abbreviated to \fBq\fP. +.ip "\fBreply\fP or \fBrespond\fP\ \ " +Frame a reply to a single message. +The reply will be sent to the +person who sent you the message (to which you are replying), plus all +the people who received the original message, except you. You can +add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP +tilde escapes. The subject in your reply is formed by prefacing the +subject in the original message with +.q "Re:" +unless it already began thus. +If the original message included a +.q "reply-to" +header field, the reply will go +.i only +to the recipient named by +.q "reply-to." +You type in your message using the same conventions available to you +through the +.b mail +command. +The \fBreply\fP (and \fBrespond\fP) command can be abbreviated to \fBr\fP. +.ip "\fBretain\fP\ \ " +Add the list of header fields named to the \fIretained list\fP. +Only the header fields in the retain list +are shown on your terminal when you print a message. +All other header fields are suppressed. +The +.b Type +and +.b Print +commands can be used to print a message in its entirety. +If +.b retain +is executed with no arguments, it lists the current set of +retained fields. +.ip "\fBsave\fP\ \ " +It is often useful to be able to save messages on related topics +in a file. The +.b save +command gives you the ability to do this. The +.b save +command takes as an argument a list of message numbers, followed by +the name of the file in which to save the messages. The messages +are appended to the named file, thus allowing one to keep several +messages in the file, stored in the order they were put there. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +An example of the +.b save +command relative to our running example is: +.(l +s 1 2 tuitionmail +.)l +.b Saved +messages are not automatically saved in +.i mbox +at quit time, nor are they selected by the +.b next +command described above, unless explicitly specified. +\fBSave\fP can be abbreviated to \fBs\fP. +.ip "\fBset\fP\ \ " +Set an option or give an option a value. Used to customize +.i Mail . +Section 5.3 contains a list of the options. Options can be +.i binary , +in which case they are +.i on +or +.i off , +or +.i valued . +To set a binary option +.i option +.i on , +do +.(l +set option +.)l +To give the valued option +.i option +the value +.i value , +do +.(l +set option=value +.)l +There must be no space before or after the ``='' sign. +If no arguments are given, all variable values are printed. +Several options can be specified in a single +.b set +command. +\fBSet\fP can be abbreviated to \fBse\fP. +.ip "\fBshell\fP\ \ " +The +.b shell +command allows you to +escape to the shell. +.b Shell +invokes an interactive shell and allows you to type commands to it. +When you leave the shell, you will return to +.i Mail . +The shell used is a default assumed by +.i Mail ; +you can override this default by setting the valued option +.q SHELL, +eg: +.(l +set SHELL=/bin/csh +.)l +\fBShell\fP can be abbreviated to \fBsh\fP. +.ip "\fBsize\fP\ \ " +Takes a message list and prints out the size in characters of each +message. +.ip "\fBsource\fP\ \ " +The +.b source +command reads +.i mail +commands from a file. It is useful when you are trying to fix your +.q .mailrc +file and you need to re-read it. +\fBSource\fP can be abbreviated to \fBso\fP. +.ip "\fBtop\fP\ \ " +The +.b top +command takes a message list and prints the first five lines +of each addressed message. +If you wish, you can change the number of lines that +.b top +prints out by setting the valued option +.q "toplines." +On a CRT terminal, +.(l +set toplines=10 +.)l +might be preferred. +\fBTop\fP can be abbreviated to \fBto\fP. +.ip "\fBtype\fP\ \ " +Same as \fBprint\fP. +Takes a message list and types out each message on the terminal. +The \fBtype\fP command can be abbreviated to \fBt\fP. +.ip "\fBundelete\fP \ \" +Takes a message list and marks each message as \fInot\fP +being deleted. +\fBUndelete\fP can be abbreviated to \fBu\fP. +.ip "\fBunread\fP\ \ " +Takes a message list and marks each message as +.i not +having been read. +\fBUnread\fP can be abbreviated to \fBU\fP. +.ip "\fBunset\fP\ \ " +Takes a list of option names and discards their remembered values; +the inverse of \fBset\fP . +.ip "\fBvisual\fP\ \ " +It is often useful to be able to invoke one of two editors, +based on the type of terminal one is using. To invoke +a display oriented editor, you can use the +.b visual +command. The operation of the +.b visual +command is otherwise identical to that of the +.b edit +command. +.ne 2v+\n(psu +.sp \n(psu +Both the +.b edit +and +.b visual +commands assume some default text editors. These default editors +can be overridden by the valued options +.q EDITOR +and +.q VISUAL +for the standard and screen editors. You might want to do: +.(l +set EDITOR=/usr/ucb/ex VISUAL=/usr/ucb/vi +.)l +\fBVisual\fP can be abbreviated to \fBv\fP. +.ip "\fBwrite\fP\ \ " +The +.b save +command always writes the entire message, including the headers, +into the file. If you want to write just the message itself, you +can use the +.b write +command. The +.b write +command has the same syntax as the +.b save +command, and can be abbreviated to simply +.b w . +Thus, we could write the second message by doing: +.(l +w 2 file.c +.)l +As suggested by this example, the +.b write +command is useful for such tasks as sending and receiving +source program text over the message system. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +.ip "\fBz\fP\ \ " +.i Mail +presents message headers in windowfuls as described under +the +.b headers +command. +You can move +.i Mail's +attention forward to the next window by giving the +.(l +z+ +.)l +command. Analogously, you can move to the previous window with: +.(l +z\- +.)l +.sh 2 "Custom options" +.pp +Throughout this manual, we have seen examples of binary and valued options. +This section describes each of the options in alphabetical order, including +some that you have not seen yet. +To avoid confusion, please note that the options are either +all lower case letters or all upper case letters. When I start a sentence +such as: +.q "Ask" +causes +.i Mail +to prompt you for a subject header, +I am only capitalizing +.q ask +as a courtesy to English. +.ip "\fBEDITOR\fP\ \ " +The valued option +.q EDITOR +defines the pathname of the text editor to be used in the +.b edit +command and ~e. If not defined, a standard editor is used. +.ip "\fBPAGER\fP\ \ " +Pathname of the program to use for paginating output when +it exceeds \fIcrt\fP lines. +A default paginator is used if this option is not defined. +.ip "\fBSHELL\fP\ \ " +The valued option +.q SHELL +gives the path name of your shell. This shell is used for the +.b ! +command and ~! escape. In addition, this shell expands +file names with shell metacharacters like * and ? in them. +.ip "\fBVISUAL\fP\ \ " +The valued option +.q VISUAL +defines the pathname of the screen editor to be used in the +.b visual +command +and ~v escape. A standard screen editor is used if you do not define one. +.ip "\fBappend\fP\ \ " +The +.q append +option is binary and +causes messages saved in +.i mbox +to be appended to the end rather than prepended. +Normally, \fIMail\fP will put messages in \fImbox\fP +in the same order that the system puts messages in your system mailbox. +By setting +.q append, +you are requesting that +.i mbox +be appended to regardless. It is in any event quicker to append. +.ip "\fBask\fP\ \ " +.q "Ask" +is a binary option which +causes +.i Mail +to prompt you for the subject of each message you send. +If you respond with simply a newline, no subject field will be sent. +.ip "\fBaskcc\fP\ \ " +.q Askcc +is a binary option which +causes you to be prompted for additional carbon copy recipients at the +end of each message. Responding with a newline shows your +satisfaction with the current list. +.ip "\fBautoprint\fP\ \ " +.q Autoprint +is a binary option which +causes the +.b delete +command to behave like +.b dp +\*- thus, after deleting a message, the next one will be typed +automatically. This is useful when quickly scanning and deleting +messages in your mailbox. +.ip "\fBcrt\fP \ \ " +The valued option +.I crt +is used as a threshold to determine how long a message must +be before +.b PAGER +is used to read it. +.ip "\fBdebug\fP \ \ " +The binary option +.q debug +causes debugging information to be displayed. Use of this +option is the same as using the \fB\-d\fP command line flag. +.ip "\fBdot\fP\ \ " +.q Dot +is a binary option which, if set, causes +.i Mail +to interpret a period alone on a line as the terminator +of the message you are sending. +.ip "\fBescape\fP\ \ " +To allow you to change the escape character used when sending +mail, you can set the valued option +.q escape. +Only the first character of the +.q escape +option is used, and it must be doubled if it is to appear as +the first character of a line of your message. If you change your escape +character, then ~ loses all its special meaning, and need no longer be doubled +at the beginning of a line. +.ip "\fBfolder\fP\ \ " +The name of the directory to use for storing folders of messages. +If this name begins with a `/' +.i Mail +considers it to be an absolute pathname; otherwise, the folder directory +is found relative to your home directory. +.ip "\fBhold\fP\ \ " +The binary option +.q hold +causes messages that have been read but not manually dealt with +to be held in the system mailbox. This prevents such messages from +being automatically swept into your \fImbox\fP file. +.ip "\fBignore\fP\ \ " +The binary option +.q ignore +causes \s-2RUBOUT\s0 characters from your terminal to be ignored and echoed +as @'s while you are sending mail. \s-2RUBOUT\s0 characters retain their +original meaning in +.i Mail +command mode. +Setting the +.q ignore +option is equivalent to supplying the +.b \-i +flag on the command line as described in section 6. +.ip "\fBignoreeof\fP\ \ " +An option related to +.q dot +is +.q ignoreeof +which makes +.i Mail +refuse to accept a control\-d as the end of a message. +.q Ignoreeof +also applies to +.i Mail +command mode. +.ip "\fBkeep\fP\ \ " +The +.q keep +option causes +.i Mail +to truncate your system mailbox instead of deleting it when it +is empty. This is useful if you elect to protect your mailbox, which +you would do with the shell command: +.(l +chmod 600 /usr/spool/mail/yourname +.)l +where +.i yourname +is your login name. If you do not do this, anyone can probably read +your mail, although people usually don't. +.ip "\fBkeepsave\fP\ \ " +When you +.b save +a message, +.i Mail +usually discards it when you +.b quit . +To retain all saved messages, set the +.q keepsave +option. +.ip "\fBmetoo\fP\ \ " +When sending mail to an alias, +.i Mail +makes sure that if you are included in the alias, that mail will not +be sent to you. This is useful if a single alias is being used by +all members of the group. If however, you wish to receive a copy of +all the messages you send to the alias, you can set the binary option +.q metoo. +.ip "\fBnoheader\fP\ \ " +The binary option +.q noheader +suppresses the printing of the version and headers when +.i Mail +is first invoked. Setting this option is the same as using +.b \-N +on the command line. +.ip "\fBnosave\fP\ \ " +Normally, +when you abort a message with two \s-2RUBOUTs\s0, +.i Mail +copies the partial letter to the file +.q dead.letter +in your home directory. Setting the binary option +.q nosave +prevents this. +.ip "\fBReplyall\fP\ \ " +Reverses the sense of +.i reply +and +.i Reply +commands. +.ip "\fBquiet\fP\ \ " +The binary option +.q quiet +suppresses the printing of the version when +.i Mail +is first invoked, +as well as printing the for example +.q "Message 4:" +from the +.b type +command. +.ip "\fBrecord\fP\ \ " +If you love to keep records, then the +valued option +.q record +can be set to the name of a file to save your outgoing mail. +Each new message you send is appended to the end of the file. +.ip "\fBscreen\fP\ \ " +When +.i Mail +initially prints the message headers, it determines the number to +print by looking at the speed of your terminal. The faster your +terminal, the more it prints. +The valued option +.q screen +overrides this calculation and +specifies how many message headers you want printed. +This number is also used for scrolling with the +.b z +command. +.ip "\fBsendmail\fP\ \ " +To use an alternate mail delivery system, set the +.q sendmail +option to the full pathname of the program to use. Note: this is not +for everyone! Most people should use the default delivery system. +.ip "\fBtoplines\fP\ \ " +The valued option +.q toplines +defines the number of lines that the +.q top +command will print out instead of the default five lines. +.ip "\fBverbose\fP\ \ " +The binary option "verbose" causes +.i Mail +to invoke sendmail with the +.b \-v +flag, which causes it to go into verbose mode and announce expansion +of aliases, etc. Setting the "verbose" option is equivalent to +invoking +.i Mail +with the +.b \-v +flag as described in section 6. diff --git a/usr.bin/mail/USD.doc/mail6.nr b/usr.bin/mail/USD.doc/mail6.nr new file mode 100644 index 0000000..e016234 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail6.nr @@ -0,0 +1,125 @@ +.\" 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. +.\" +.\" @(#)mail6.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Command line options" +.pp +This section describes command line options for +.i Mail +and what they are used for. +.ip \-N +Suppress the initial printing of headers. +.ip \-d +Turn on debugging information. Not of general interest. +.ip "\-f file\ \ " +Show the messages in +.i file +instead of your system mailbox. If +.i file +is omitted, +.i Mail +reads +.i mbox +in your home directory. +.ip \-i +Ignore tty interrupt signals. Useful on noisy phone lines, which +generate spurious RUBOUT or DELETE characters. It's usually +more effective to change your interrupt character to control\-c, +for which see the +.i stty +shell command. +.ip \-n +Inhibit reading of /usr/lib/Mail.rc. Not generally useful, since +/usr/lib/Mail.rc is usually empty. +.ip "\-s string" +Used for sending mail. +.i String +is used as the subject of the message being composed. If +.i string +contains blanks, you must surround it with quote marks. +.ip "\-u name" +Read +.i names's +mail instead of your own. Unwitting others often neglect to protect +their mailboxes, but discretion is advised. Essentially, +.b "\-u user" +is a shorthand way of doing +.b "\-f /usr/spool/mail/user". +.ip "\-v" +Use the +.b \-v +flag when invoking sendmail. This feature may also be enabled +by setting the the option "verbose". +.pp +The following command line flags are also recognized, but are +intended for use by programs invoking +.i Mail +and not for people. +.ip "\-T file" +Arrange to print on +.i file +the contents of the +.i article-id +fields of all messages that were either read or deleted. +.b \-T +is for the +.i readnews +program and should NOT be used for reading your mail. +.ip "\-h number" +Pass on hop count information. +.i Mail +will take the number, increment it, and pass it with +.b \-h +to the mail delivery system. +.b \-h +only has effect when sending mail and is used for network mail +forwarding. +.ip "\-r name" +Used for network mail forwarding: interpret +.i name +as the sender of the message. The +.i name +and +.b \-r +are simply sent along to the mail delivery system. Also, +.i Mail +will wait for the message to be sent and return the exit status. +Also restricts formatting of message. +.pp +Note that +.b \-h +and +.b \-r , +which are for network mail forwarding, are not used in practice +since mail forwarding is now handled separately. They may +disappear soon. diff --git a/usr.bin/mail/USD.doc/mail7.nr b/usr.bin/mail/USD.doc/mail7.nr new file mode 100644 index 0000000..0b2590b --- /dev/null +++ b/usr.bin/mail/USD.doc/mail7.nr @@ -0,0 +1,107 @@ +.\" 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. +.\" +.\" @(#)mail7.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Format of messages" +.pp +This section describes the format of messages. +Messages begin with a +.i from +line, which consists of the word +.q From +followed by a user name, followed by anything, followed by +a date in the format returned by the +.i ctime +library routine described in section 3 of the Unix Programmer's +Manual. A possible +.i ctime +format date is: +.(l +Tue Dec 1 10:58:23 1981 +.)l +The +.i ctime +date may be optionally followed by a single space and a +time zone indication, which +should be three capital letters, such as PDT. +.pp +Following the +.i from +line are zero or more +.i "header field" +lines. +Each header field line is of the form: +.(l +name: information +.)l +.i Name +can be anything, but only certain header fields are recognized as +having any meaning. The recognized header fields are: +.i article-id , +.i bcc , +.i cc , +.i from , +.i reply-to , +.i sender , +.i subject , +and +.i to . +Other header fields are also significant to other systems; see, +for example, the current Arpanet message standard for much more +information on this topic. +A header field can be continued onto following lines by making the +first character on the following line a space or tab character. +.pp +If any headers are present, they must be followed by a blank line. +The part that follows is called the +.i body +of the message, and must be ASCII text, not containing null characters. +Each line in the message body must be no longer than 512 characters and +terminated with an ASCII newline character. +If binary data must be passed through the mail system, it is suggested +that this data be encoded in a system which encodes six bits into +a printable character (i.e.: uuencode). +For example, one could use the upper and lower case letters, the digits, +and the characters comma and period to make up the 64 characters. +Then, one can send a 16-bit binary number +as three characters. These characters should be packed into lines, +preferably lines about 70 characters long as long lines are transmitted +more efficiently. +.pp +The message delivery system always adds a blank line to the end of +each message. This blank line must not be deleted. +.pp +The UUCP message delivery system sometimes adds a blank line to +the end of a message each time it is forwarded through a machine. +.pp +It should be noted that some network transport protocols enforce +limits to the lengths of messages. diff --git a/usr.bin/mail/USD.doc/mail8.nr b/usr.bin/mail/USD.doc/mail8.nr new file mode 100644 index 0000000..e8e056b --- /dev/null +++ b/usr.bin/mail/USD.doc/mail8.nr @@ -0,0 +1,75 @@ +.\" 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. +.\" +.\" @(#)mail8.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Glossary" +.pp +This section contains the definitions of a few phrases +peculiar to +.i Mail . +.ip "\fIalias\fP" +An alternative name for a person or list of people. +.ip "\fIflag\fP" +An option, given on the command line of +.i Mail , +prefaced with a \-. For example, +.b \-f +is a flag. +.ip "\fIheader field\fP" +At the beginning of a message, a line which contains information +that is part of the structure of the message. Popular header fields +include +.i to , +.i cc , +and +.i subject . +.ip "\fImail\ \ \fP" +A collection of messages. Often used in the phrase, +.q "Have you read your mail?" +.ip "\fImailbox\fP" +The place where your mail is stored, typically in the directory +/usr/spool/mail. +.ip "\fImessage\fP" +A single letter from someone, initially stored in your +.i mailbox . +.ip "\fImessage list\fP" +A string used in +.i Mail +command mode to describe a sequence of messages. +.ip "\fIoption\fP" +A piece of special purpose information used to tailor +.i Mail +to your taste. +Options are specified with the +.b set +command. diff --git a/usr.bin/mail/USD.doc/mail9.nr b/usr.bin/mail/USD.doc/mail9.nr new file mode 100644 index 0000000..99f7518 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail9.nr @@ -0,0 +1,203 @@ +.\" 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. +.\" +.\" @(#)mail9.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Summary of commands, options, and escapes" +.pp +This section gives a quick summary of the +.i Mail +commands, binary and valued options, and tilde escapes. +.pp +The following table describes the commands: +.TS +center ; +c ci +lb l. +Command Description +_ ++ Same as \fBnext\fP +- Back up to previous message +? Print brief summary of \fIMail\fP commands +! Single command escape to shell +Print Type message with ignored fields +Reply Reply to author of message only +Respond Same as \fBReply\fP +Type Type message with ignored fields +alias Define an alias as a set of user names +alternates List other names you are known by +chdir Change working directory, home by default +copy Copy a message to a file or folder +delete Delete a list of messages +dp Same as \fBdt\fP +dt Delete current message, type next message +edit Edit a list of messages +else Start of else part of conditional; see \fBif\fP +endif End of conditional statement; see \fBif\fP +exit Leave mail without changing anything +file Interrogate/change current mail file +folder Same as \fBfile\fP +folders List the folders in your folder directory +from List headers of a list of messages +headers List current window of messages +help Same as \fB?\fP +hold Same as \fBpreserve\fP +if Conditional execution of \fIMail\fP commands +ignore Set/examine list of ignored header fields +list List valid \fIMail\fP commands +local List other names for the local host +mail Send mail to specified names +mbox Arrange to save a list of messages in \fImbox\fP +next Go to next message and type it +preserve Arrange to leave list of messages in system mailbox +print Print messages +quit Leave \fIMail\fP; update system mailbox, \fImbox\fP as appropriate +reply Compose a reply to a message +respond Same as \fBreply\fP +retain Supersedes \fBignore\fP +save Append messages, headers included, on a file +set Set binary or valued options +shell Invoke an interactive shell +size Prints out size of message list +source Read \fImail\fP commands from a file +top Print first so many (5 by default) lines of list of messages +type Same as \fBprint\fP +undelete Undelete list of messages +unread Marks list of messages as not been read +unset Undo the operation of a \fBset\fP +visual Invoke visual editor on a list of messages +write Append messages to a file, don't include headers +xit Same as \fBexit\fP +z Scroll to next/previous screenful of headers +.TE +.bp +.(b +.pp +The following table describes the options. Each option is +shown as being either a binary or valued option. +.TS +center; +c ci ci +l ci l. +Option Type Description +_ +EDITOR valued Pathname of editor for ~e and \fBedit\fP +PAGER valued Pathname of paginator for \fBPrint\fP, \fBprint\fP, \fBType\fP and \fBtype\fP +SHELL valued Pathname of shell for \fBshell\fP, ~! and \fB!\fP +VISUAL valued Pathname of screen editor for ~v, \fBvisual\fP +append binary Always append messages to end of \fImbox\fP +ask binary Prompt user for Subject: field when sending +askcc binary Prompt user for additional Cc's at end of message +autoprint binary Print next message after \fBdelete\fP +crt valued Minimum number of lines before using \fBPAGER\fP +debug binary Print out debugging information +dot binary Accept . alone on line to terminate message input +escape valued Escape character to be used instead of\ \ ~ +folder valued Directory to store folders in +hold binary Hold messages in system mailbox by default +ignore binary Ignore \s-2RUBOUT\s0 while sending mail +ignoreeof binary Don't terminate letters/command input with \fB\(uaD\fP +keep binary Don't unlink system mailbox when empty +keepsave binary Don't delete \fBsave\fPd messages by default +metoo binary Include sending user in aliases +noheader binary Suppress initial printing of version and headers +nosave binary Don't save partial letter in \fIdead.letter\fP +quiet binary Suppress printing of \fIMail\fP version and message numbers +record valued File to save all outgoing mail in +screen valued Size of window of message headers for \fBz\fP, etc. +sendmail valued Choose alternate mail delivery system +toplines valued Number of lines to print in \fBtop\fP +verbose binary Invoke sendmail with the \fB\-v\fP flag +.TE +.)b +.(b +.pp +The following table summarizes the tilde escapes available +while sending mail. +.TS +center; +c ci ci +l li l. +Escape Arguments Description +_ +~! command Execute shell command +~b name ... Add names to "blind" Cc: list +~c name ... Add names to Cc: field +~d Read \fIdead.letter\fP into message +~e Invoke text editor on partial message +~f messages Read named messages +~h Edit the header fields +~m messages Read named messages, right shift by tab +~p Print message entered so far +~q Abort entry of letter; like \s-2RUBOUT\s0 +~r filename Read file into message +~s string Set Subject: field to \fIstring\fP +~t name ... Add names to To: field +~v Invoke screen editor on message +~w filename Write message on file +~| command Pipe message through \fIcommand\fP +~: Mail command Execute a \fIMail\fP command +~~ string Quote a ~ in front of \fIstring\fP +.TE +.)b +.(b +.pp +The following table shows the command line flags that +.i Mail +accepts: +.TS +center; +c c +l a. +Flag Description +_ +\-N Suppress the initial printing of headers +\-T \fIfile\fP Article-id's of read/deleted messages to \fIfile\fP +\-d Turn on debugging +\-f \fIfile\fP Show messages in \fIfile\fP or \fI~/mbox\fP +\-h \fInumber\fP Pass on hop count for mail forwarding +\-i Ignore tty interrupt signals +\-n Inhibit reading of /usr/lib/Mail.rc +\-r \fIname\fP Pass on \fIname\fP for mail forwarding +\-s \fIstring\fP Use \fIstring\fP as subject in outgoing mail +\-u \fIname\fP Read \fIname's\fP mail instead of your own +\-v Invoke sendmail with the \fB\-v\fP flag +.TE +.)b +.lp +Notes: +.b \-T , +.b \-d , +.b \-h , +and +.b \-r +are not for human use. diff --git a/usr.bin/mail/USD.doc/maila.nr b/usr.bin/mail/USD.doc/maila.nr new file mode 100644 index 0000000..84b01fe --- /dev/null +++ b/usr.bin/mail/USD.doc/maila.nr @@ -0,0 +1,33 @@ +.\" 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. +.\" +.\" @(#)maila.nr 8.1 (Berkeley) 6/8/93 +.\" diff --git a/usr.bin/mail/aux.c b/usr.bin/mail/aux.c new file mode 100644 index 0000000..f4c2acd --- /dev/null +++ b/usr.bin/mail/aux.c @@ -0,0 +1,705 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Auxiliary functions. + */ + +/* + * Return a pointer to a dynamic copy of the argument. + */ +char * +savestr(str) + char *str; +{ + char *new; + int size = strlen(str) + 1; + + if ((new = salloc(size)) != NOSTR) + bcopy(str, new, size); + return new; +} + +/* + * Make a copy of new argument incorporating old one. + */ +char * +save2str(str, old) + char *str, *old; +{ + char *new; + int newsize = strlen(str) + 1; + int oldsize = old ? strlen(old) + 1 : 0; + + if ((new = salloc(newsize + oldsize)) != NOSTR) { + if (oldsize) { + bcopy(old, new, oldsize); + new[oldsize - 1] = ' '; + } + bcopy(str, new + oldsize, newsize); + } + return new; +} + +/* + * Announce a fatal error and die. + */ +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +panic(const char *fmt, ...) +#else +panic(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "panic: "); + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + fflush(stderr); + abort(); +} + +/* + * Touch the named message by setting its MTOUCH flag. + * Touched messages have the effect of not being sent + * back to the system mailbox on exit. + */ +void +touch(mp) + register struct message *mp; +{ + + mp->m_flag |= MTOUCH; + if ((mp->m_flag & MREAD) == 0) + mp->m_flag |= MREAD|MSTATUS; +} + +/* + * Test to see if the passed file name is a directory. + * Return true if it is. + */ +int +isdir(name) + char name[]; +{ + struct stat sbuf; + + if (stat(name, &sbuf) < 0) + return(0); + return((sbuf.st_mode & S_IFMT) == S_IFDIR); +} + +/* + * Count the number of arguments in the given string raw list. + */ +int +argcount(argv) + char **argv; +{ + register char **ap; + + for (ap = argv; *ap++ != NOSTR;) + ; + return ap - argv - 1; +} + +/* + * Return the desired header line from the passed message + * pointer (or NOSTR if the desired header field is not available). + */ +char * +hfield(field, mp) + char field[]; + struct message *mp; +{ + register FILE *ibuf; + char linebuf[LINESIZE]; + register int lc; + register char *hfield; + char *colon, *oldhfield = NOSTR; + + ibuf = setinput(mp); + if ((lc = mp->m_lines - 1) < 0) + return NOSTR; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return NOSTR; + while (lc > 0) { + if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) + return oldhfield; + if (hfield = ishfield(linebuf, colon, field)) + oldhfield = save2str(hfield, oldhfield); + } + return oldhfield; +} + +/* + * Return the next header field found in the given message. + * Return >= 0 if something found, < 0 elsewise. + * "colon" is set to point to the colon in the header. + * Must deal with \ continuations & other such fraud. + */ +int +gethfield(f, linebuf, rem, colon) + register FILE *f; + char linebuf[]; + register int rem; + char **colon; +{ + char line2[LINESIZE]; + register char *cp, *cp2; + register int c; + + for (;;) { + if (--rem < 0) + return -1; + if ((c = readline(f, linebuf, LINESIZE)) <= 0) + return -1; + for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':'; + cp++) + ; + if (*cp != ':' || cp == linebuf) + continue; + /* + * I guess we got a headline. + * Handle wraparounding + */ + *colon = cp; + cp = linebuf + c; + for (;;) { + while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) + ; + cp++; + if (rem <= 0) + break; + ungetc(c = getc(f), f); + if (c != ' ' && c != '\t') + break; + if ((c = readline(f, line2, LINESIZE)) < 0) + break; + rem--; + for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) + ; + c -= cp2 - line2; + if (cp + c >= linebuf + LINESIZE - 2) + break; + *cp++ = ' '; + bcopy(cp2, cp, c); + cp += c; + } + *cp = 0; + return rem; + } + /* NOTREACHED */ +} + +/* + * Check whether the passed line is a header line of + * the desired breed. Return the field body, or 0. + */ + +char* +ishfield(linebuf, colon, field) + char linebuf[], field[]; + char *colon; +{ + register char *cp = colon; + + *cp = 0; + if (strcasecmp(linebuf, field) != 0) { + *cp = ':'; + return 0; + } + *cp = ':'; + for (cp++; *cp == ' ' || *cp == '\t'; cp++) + ; + return cp; +} + +/* + * Copy a string, lowercasing it as we go. + */ +void +istrcpy(dest, src) + register char *dest, *src; +{ + + do { + if (isupper(*src)) + *dest++ = tolower(*src); + else + *dest++ = *src; + } while (*src++ != 0); +} + +/* + * The following code deals with input stacking to do source + * commands. All but the current file pointer are saved on + * the stack. + */ + +static int ssp; /* Top of file stack */ +struct sstack { + FILE *s_file; /* File we were in. */ + int s_cond; /* Saved state of conditionals */ + int s_loading; /* Loading .mailrc, etc. */ +} sstack[NOFILE]; + +/* + * Pushdown current input file and switch to a new one. + * Set the global flag "sourcing" so that others will realize + * that they are no longer reading from a tty (in all probability). + */ +int +source(arglist) + char **arglist; +{ + FILE *fi; + char *cp; + + if ((cp = expand(*arglist)) == NOSTR) + return(1); + if ((fi = Fopen(cp, "r")) == NULL) { + perror(cp); + return(1); + } + if (ssp >= NOFILE - 1) { + printf("Too much \"sourcing\" going on.\n"); + Fclose(fi); + return(1); + } + sstack[ssp].s_file = input; + sstack[ssp].s_cond = cond; + sstack[ssp].s_loading = loading; + ssp++; + loading = 0; + cond = CANY; + input = fi; + sourcing++; + return(0); +} + +/* + * Pop the current input back to the previous level. + * Update the "sourcing" flag as appropriate. + */ +int +unstack() +{ + if (ssp <= 0) { + printf("\"Source\" stack over-pop.\n"); + sourcing = 0; + return(1); + } + Fclose(input); + if (cond != CANY) + printf("Unmatched \"if\"\n"); + ssp--; + cond = sstack[ssp].s_cond; + loading = sstack[ssp].s_loading; + input = sstack[ssp].s_file; + if (ssp == 0) + sourcing = loading; + return(0); +} + +/* + * Touch the indicated file. + * This is nifty for the shell. + */ +void +alter(name) + char *name; +{ + struct stat sb; + struct timeval tv[2]; + time_t time(); + + if (stat(name, &sb)) + return; + tv[0].tv_sec = time((time_t *)0) + 1; + tv[1].tv_sec = sb.st_mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + (void)utimes(name, tv); +} + +/* + * Examine the passed line buffer and + * return true if it is all blanks and tabs. + */ +int +blankline(linebuf) + char linebuf[]; +{ + register char *cp; + + for (cp = linebuf; *cp; cp++) + if (*cp != ' ' && *cp != '\t') + return(0); + return(1); +} + +/* + * Get sender's name from this message. If the message has + * a bunch of arpanet stuff in it, we may have to skin the name + * before returning it. + */ +char * +nameof(mp, reptype) + register struct message *mp; + int reptype; +{ + register char *cp, *cp2; + + cp = skin(name1(mp, reptype)); + if (reptype != 0 || charcount(cp, '!') < 2) + return(cp); + cp2 = rindex(cp, '!'); + cp2--; + while (cp2 > cp && *cp2 != '!') + cp2--; + if (*cp2 == '!') + return(cp2 + 1); + return(cp); +} + +/* + * Start of a "comment". + * Ignore it. + */ +char * +skip_comment(cp) + register char *cp; +{ + register nesting = 1; + + for (; nesting > 0 && *cp; cp++) { + switch (*cp) { + case '\\': + if (cp[1]) + cp++; + break; + case '(': + nesting++; + break; + case ')': + nesting--; + break; + } + } + return cp; +} + +/* + * Skin an arpa net address according to the RFC 822 interpretation + * of "host-phrase." + */ +char * +skin(name) + char *name; +{ + register int c; + register char *cp, *cp2; + char *bufend; + int gotlt, lastsp; + char nbuf[BUFSIZ]; + + if (name == NOSTR) + return(NOSTR); + if (index(name, '(') == NOSTR && index(name, '<') == NOSTR + && index(name, ' ') == NOSTR) + return(name); + gotlt = 0; + lastsp = 0; + bufend = nbuf; + for (cp = name, cp2 = bufend; c = *cp++; ) { + switch (c) { + case '(': + cp = skip_comment(cp); + lastsp = 0; + break; + + case '"': + /* + * Start of a "quoted-string". + * Copy it in its entirety. + */ + while (c = *cp) { + cp++; + if (c == '"') + break; + if (c != '\\') + *cp2++ = c; + else if (c = *cp) { + *cp2++ = c; + cp++; + } + } + lastsp = 0; + break; + + case ' ': + if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') + cp += 3, *cp2++ = '@'; + else + if (cp[0] == '@' && cp[1] == ' ') + cp += 2, *cp2++ = '@'; + else + lastsp = 1; + break; + + case '<': + cp2 = bufend; + gotlt++; + lastsp = 0; + break; + + case '>': + if (gotlt) { + gotlt = 0; + while ((c = *cp) && c != ',') { + cp++; + if (c == '(') + cp = skip_comment(cp); + else if (c == '"') + while (c = *cp) { + cp++; + if (c == '"') + break; + if (c == '\\' && *cp) + cp++; + } + } + lastsp = 0; + break; + } + /* Fall into . . . */ + + default: + if (lastsp) { + lastsp = 0; + *cp2++ = ' '; + } + *cp2++ = c; + if (c == ',' && !gotlt) { + *cp2++ = ' '; + for (; *cp == ' '; cp++) + ; + lastsp = 0; + bufend = cp2; + } + } + } + *cp2 = 0; + + return(savestr(nbuf)); +} + +/* + * Fetch the sender's name from the passed message. + * Reptype can be + * 0 -- get sender's name for display purposes + * 1 -- get sender's name for reply + * 2 -- get sender's name for Reply + */ +char * +name1(mp, reptype) + register struct message *mp; + int reptype; +{ + char namebuf[LINESIZE]; + char linebuf[LINESIZE]; + register char *cp, *cp2; + register FILE *ibuf; + int first = 1; + + if ((cp = hfield("from", mp)) != NOSTR) + return cp; + if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR) + return cp; + ibuf = setinput(mp); + namebuf[0] = 0; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return(savestr(namebuf)); +newname: + for (cp = linebuf; *cp && *cp != ' '; cp++) + ; + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + for (cp2 = &namebuf[strlen(namebuf)]; + *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;) + *cp2++ = *cp++; + *cp2 = '\0'; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return(savestr(namebuf)); + if ((cp = index(linebuf, 'F')) == NULL) + return(savestr(namebuf)); + if (strncmp(cp, "From", 4) != 0) + return(savestr(namebuf)); + while ((cp = index(cp, 'r')) != NULL) { + if (strncmp(cp, "remote", 6) == 0) { + if ((cp = index(cp, 'f')) == NULL) + break; + if (strncmp(cp, "from", 4) != 0) + break; + if ((cp = index(cp, ' ')) == NULL) + break; + cp++; + if (first) { + strcpy(namebuf, cp); + first = 0; + } else + strcpy(rindex(namebuf, '!')+1, cp); + strcat(namebuf, "!"); + goto newname; + } + cp++; + } + return(savestr(namebuf)); +} + +/* + * Count the occurances of c in str + */ +int +charcount(str, c) + char *str; + int c; +{ + register char *cp; + register int i; + + for (i = 0, cp = str; *cp; cp++) + if (*cp == c) + i++; + return(i); +} + +/* + * Are any of the characters in the two strings the same? + */ +int +anyof(s1, s2) + register char *s1, *s2; +{ + + while (*s1) + if (index(s2, *s1++)) + return 1; + return 0; +} + +/* + * Convert c to upper case + */ +int +raise(c) + register int c; +{ + + if (islower(c)) + return toupper(c); + return c; +} + +/* + * Copy s1 to s2, return pointer to null in s2. + */ +char * +copy(s1, s2) + register char *s1, *s2; +{ + + while (*s2++ = *s1++) + ; + return s2 - 1; +} + +/* + * See if the given header field is supposed to be ignored. + */ +int +isign(field, ignore) + char *field; + struct ignoretab ignore[2]; +{ + char realfld[BUFSIZ]; + + if (ignore == ignoreall) + return 1; + /* + * Lower-case the string, so that "Status" and "status" + * will hash to the same place. + */ + istrcpy(realfld, field); + if (ignore[1].i_count > 0) + return (!member(realfld, ignore + 1)); + else + return (member(realfld, ignore)); +} + +int +member(realfield, table) + register char *realfield; + struct ignoretab *table; +{ + register struct ignore *igp; + + for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link) + if (*igp->i_field == *realfield && + equal(igp->i_field, realfield)) + return (1); + return (0); +} diff --git a/usr.bin/mail/cmd1.c b/usr.bin/mail/cmd1.c new file mode 100644 index 0000000..e83a036 --- /dev/null +++ b/usr.bin/mail/cmd1.c @@ -0,0 +1,451 @@ +/*- + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * User commands. + */ + +/* + * Print the current active headings. + * Don't change dot if invoker didn't give an argument. + */ + +static int screen; + +int +headers(msgvec) + int *msgvec; +{ + register int n, mesg, flag; + register struct message *mp; + int size; + + size = screensize(); + n = msgvec[0]; + if (n != 0) + screen = (n-1)/size; + if (screen < 0) + screen = 0; + mp = &message[screen * size]; + if (mp >= &message[msgCount]) + mp = &message[msgCount - size]; + if (mp < &message[0]) + mp = &message[0]; + flag = 0; + mesg = mp - &message[0]; + if (dot != &message[n-1]) + dot = mp; + for (; mp < &message[msgCount]; mp++) { + mesg++; + if (mp->m_flag & MDELETED) + continue; + if (flag++ >= size) + break; + printhead(mesg); + } + if (flag == 0) { + printf("No more mail.\n"); + return(1); + } + return(0); +} + +/* + * Scroll to the next/previous screen + */ +int +scroll(arg) + char arg[]; +{ + register int s, size; + int cur[1]; + + cur[0] = 0; + size = screensize(); + s = screen; + switch (*arg) { + case 0: + case '+': + s++; + if (s * size > msgCount) { + printf("On last screenful of messages\n"); + return(0); + } + screen = s; + break; + + case '-': + if (--s < 0) { + printf("On first screenful of messages\n"); + return(0); + } + screen = s; + break; + + default: + printf("Unrecognized scrolling command \"%s\"\n", arg); + return(1); + } + return(headers(cur)); +} + +/* + * Compute screen size. + */ +int +screensize() +{ + int s; + char *cp; + + if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0) + return s; + return screenheight - 4; +} + +/* + * Print out the headlines for each message + * in the passed message list. + */ +int +from(msgvec) + int *msgvec; +{ + register int *ip; + + for (ip = msgvec; *ip != NULL; ip++) + printhead(*ip); + if (--ip >= msgvec) + dot = &message[*ip - 1]; + return(0); +} + +/* + * Print out the header of a specific message. + * This is a slight improvement to the standard one. + */ +void +printhead(mesg) + int mesg; +{ + struct message *mp; + char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; + char pbuf[BUFSIZ]; + struct headline hl; + int subjlen; + char *name; + + mp = &message[mesg-1]; + (void) readline(setinput(mp), headline, LINESIZE); + if ((subjline = hfield("subject", mp)) == NOSTR) + subjline = hfield("subj", mp); + /* + * Bletch! + */ + curind = dot == mp ? '>' : ' '; + dispc = ' '; + if (mp->m_flag & MSAVED) + dispc = '*'; + if (mp->m_flag & MPRESERVE) + dispc = 'P'; + if ((mp->m_flag & (MREAD|MNEW)) == MNEW) + dispc = 'N'; + if ((mp->m_flag & (MREAD|MNEW)) == 0) + dispc = 'U'; + if (mp->m_flag & MBOX) + dispc = 'M'; + parse(headline, &hl, pbuf); + sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size); + subjlen = screenwidth - 50 - strlen(wcount); + name = value("show-rcpt") != NOSTR ? + skin(hfield("to", mp)) : nameof(mp, 0); + if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */ + printf("%c%c%3d %-20.20s %16.16s %s\n", + curind, dispc, mesg, name, hl.l_date, wcount); + else + printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", + curind, dispc, mesg, name, hl.l_date, wcount, + subjlen, subjline); +} + +/* + * Print out the value of dot. + */ +int +pdot() +{ + printf("%d\n", dot - &message[0] + 1); + return(0); +} + +/* + * Print out all the possible commands. + */ +int +pcmdlist() +{ + register struct cmd *cp; + register int cc; + extern struct cmd cmdtab[]; + + printf("Commands are:\n"); + for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { + cc += strlen(cp->c_name) + 2; + if (cc > 72) { + printf("\n"); + cc = strlen(cp->c_name) + 2; + } + if ((cp+1)->c_name != NOSTR) + printf("%s, ", cp->c_name); + else + printf("%s\n", cp->c_name); + } + return(0); +} + +/* + * Paginate messages, honor ignored fields. + */ +int +more(msgvec) + int *msgvec; +{ + return (type1(msgvec, 1, 1)); +} + +/* + * Paginate messages, even printing ignored fields. + */ +int +More(msgvec) + int *msgvec; +{ + + return (type1(msgvec, 0, 1)); +} + +/* + * Type out messages, honor ignored fields. + */ +int +type(msgvec) + int *msgvec; +{ + + return(type1(msgvec, 1, 0)); +} + +/* + * Type out messages, even printing ignored fields. + */ +int +Type(msgvec) + int *msgvec; +{ + + return(type1(msgvec, 0, 0)); +} + +/* + * Type out the messages requested. + */ +jmp_buf pipestop; +int +type1(msgvec, doign, page) + int *msgvec; + int doign, page; +{ + register *ip; + register struct message *mp; + register char *cp; + int nlines; + FILE *obuf; + + obuf = stdout; + if (setjmp(pipestop)) + goto close_pipe; + if (value("interactive") != NOSTR && + (page || (cp = value("crt")) != NOSTR)) { + nlines = 0; + if (!page) { + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) + nlines += message[*ip - 1].m_lines; + } + if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { + cp = value("PAGER"); + if (cp == NULL || *cp == '\0') + cp = _PATH_MORE; + obuf = Popen(cp, "w"); + if (obuf == NULL) { + perror(cp); + obuf = stdout; + } else + signal(SIGPIPE, brokpipe); + } + } + for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + if (value("quiet") == NOSTR) + fprintf(obuf, "Message %d:\n", *ip); + (void) send(mp, obuf, doign ? ignore : 0, NOSTR); + } +close_pipe: + if (obuf != stdout) { + /* + * Ignore SIGPIPE so it can't cause a duplicate close. + */ + signal(SIGPIPE, SIG_IGN); + Pclose(obuf); + signal(SIGPIPE, SIG_DFL); + } + return(0); +} + +/* + * Respond to a broken pipe signal -- + * probably caused by quitting more. + */ +void +brokpipe(signo) + int signo; +{ + longjmp(pipestop, 1); +} + +/* + * Print the top so many lines of each desired message. + * The number of lines is taken from the variable "toplines" + * and defaults to 5. + */ +int +top(msgvec) + int *msgvec; +{ + register int *ip; + register struct message *mp; + int c, topl, lines, lineb; + char *valtop, linebuf[LINESIZE]; + FILE *ibuf; + + topl = 5; + valtop = value("toplines"); + if (valtop != NOSTR) { + topl = atoi(valtop); + if (topl < 0 || topl > 10000) + topl = 5; + } + lineb = 1; + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + if (value("quiet") == NOSTR) + printf("Message %d:\n", *ip); + ibuf = setinput(mp); + c = mp->m_lines; + if (!lineb) + printf("\n"); + for (lines = 0; lines < c && lines <= topl; lines++) { + if (readline(ibuf, linebuf, LINESIZE) < 0) + break; + puts(linebuf); + lineb = blankline(linebuf); + } + } + return(0); +} + +/* + * Touch all the given messages so that they will + * get mboxed. + */ +int +stouch(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != 0; ip++) { + dot = &message[*ip-1]; + dot->m_flag |= MTOUCH; + dot->m_flag &= ~MPRESERVE; + } + return(0); +} + +/* + * Make sure all passed messages get mboxed. + */ +int +mboxit(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != 0; ip++) { + dot = &message[*ip-1]; + dot->m_flag |= MTOUCH|MBOX; + dot->m_flag &= ~MPRESERVE; + } + return(0); +} + +/* + * List the folders the user currently has. + */ +int +folders() +{ + char dirname[BUFSIZ]; + char *cmd; + + if (getfold(dirname) < 0) { + printf("No value set for \"folder\"\n"); + return 1; + } + if ((cmd = value("LISTER")) == NOSTR) + cmd = "ls"; + (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR); + return 0; +} diff --git a/usr.bin/mail/cmd2.c b/usr.bin/mail/cmd2.c new file mode 100644 index 0000000..abe3ca9 --- /dev/null +++ b/usr.bin/mail/cmd2.c @@ -0,0 +1,530 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * More user commands. + */ + +/* + * If any arguments were given, go to the next applicable argument + * following dot, otherwise, go to the next applicable message. + * If given as first command with no arguments, print first message. + */ +int +next(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, *ip2; + int list[2], mdot; + + if (*msgvec != NULL) { + + /* + * If some messages were supplied, find the + * first applicable one following dot using + * wrap around. + */ + + mdot = dot - &message[0] + 1; + + /* + * Find the first message in the supplied + * message list which follows dot. + */ + + for (ip = msgvec; *ip != NULL; ip++) + if (*ip > mdot) + break; + if (*ip == NULL) + ip = msgvec; + ip2 = ip; + do { + mp = &message[*ip2 - 1]; + if ((mp->m_flag & MDELETED) == 0) { + dot = mp; + goto hitit; + } + if (*ip2 != NULL) + ip2++; + if (*ip2 == NULL) + ip2 = msgvec; + } while (ip2 != ip); + printf("No messages applicable\n"); + return(1); + } + + /* + * If this is the first command, select message 1. + * Note that this must exist for us to get here at all. + */ + + if (!sawcom) + goto hitit; + + /* + * Just find the next good message after dot, no + * wraparound. + */ + + for (mp = dot+1; mp < &message[msgCount]; mp++) + if ((mp->m_flag & (MDELETED|MSAVED)) == 0) + break; + if (mp >= &message[msgCount]) { + printf("At EOF\n"); + return(0); + } + dot = mp; +hitit: + /* + * Print dot. + */ + + list[0] = dot - &message[0] + 1; + list[1] = NULL; + return(type(list)); +} + +/* + * Save a message in a file. Mark the message as saved + * so we can discard when the user quits. + */ +int +save(str) + char str[]; +{ + + return save1(str, 1, "save", saveignore); +} + +/* + * Copy a message to a file without affected its saved-ness + */ +int +copycmd(str) + char str[]; +{ + + return save1(str, 0, "copy", saveignore); +} + +/* + * Save/copy the indicated messages at the end of the passed file name. + * If mark is true, mark the message "saved." + */ +int +save1(str, mark, cmd, ignore) + char str[]; + int mark; + char *cmd; + struct ignoretab *ignore; +{ + register int *ip; + register struct message *mp; + char *file, *disp; + int f, *msgvec; + FILE *obuf; + + msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); + if ((file = snarf(str, &f)) == NOSTR) + return(1); + if (!f) { + *msgvec = first(0, MMNORM); + if (*msgvec == NULL) { + printf("No messages to %s.\n", cmd); + return(1); + } + msgvec[1] = NULL; + } + if (f && getmsglist(str, msgvec, 0) < 0) + return(1); + if ((file = expand(file)) == NOSTR) + return(1); + printf("\"%s\" ", file); + fflush(stdout); + if (access(file, 0) >= 0) + disp = "[Appended]"; + else + disp = "[New file]"; + if ((obuf = Fopen(file, "a")) == NULL) { + perror(NOSTR); + return(1); + } + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + if (send(mp, obuf, ignore, NOSTR) < 0) { + perror(file); + Fclose(obuf); + return(1); + } + if (mark) + mp->m_flag |= MSAVED; + } + fflush(obuf); + if (ferror(obuf)) + perror(file); + Fclose(obuf); + printf("%s\n", disp); + return(0); +} + +/* + * Write the indicated messages at the end of the passed + * file name, minus header and trailing blank line. + */ +int +swrite(str) + char str[]; +{ + + return save1(str, 1, "write", ignoreall); +} + +/* + * Snarf the file from the end of the command line and + * return a pointer to it. If there is no file attached, + * just return NOSTR. Put a null in front of the file + * name so that the message list processing won't see it, + * unless the file name is the only thing on the line, in + * which case, return 0 in the reference flag variable. + */ + +char * +snarf(linebuf, flag) + char linebuf[]; + int *flag; +{ + register char *cp; + + *flag = 1; + cp = strlen(linebuf) + linebuf - 1; + + /* + * Strip away trailing blanks. + */ + + while (cp > linebuf && isspace(*cp)) + cp--; + *++cp = 0; + + /* + * Now search for the beginning of the file name. + */ + + while (cp > linebuf && !isspace(*cp)) + cp--; + if (*cp == '\0') { + printf("No file specified.\n"); + return(NOSTR); + } + if (isspace(*cp)) + *cp++ = 0; + else + *flag = 0; + return(cp); +} + +/* + * Delete messages. + */ +int +delete(msgvec) + int msgvec[]; +{ + delm(msgvec); + return 0; +} + +/* + * Delete messages, then type the new dot. + */ +int +deltype(msgvec) + int msgvec[]; +{ + int list[2]; + int lastdot; + + lastdot = dot - &message[0] + 1; + if (delm(msgvec) >= 0) { + list[0] = dot - &message[0] + 1; + if (list[0] > lastdot) { + touch(dot); + list[1] = NULL; + return(type(list)); + } + printf("At EOF\n"); + } else + printf("No more messages\n"); + return(0); +} + +/* + * Delete the indicated messages. + * Set dot to some nice place afterwards. + * Internal interface. + */ +int +delm(msgvec) + int *msgvec; +{ + register struct message *mp; + register *ip; + int last; + + last = NULL; + for (ip = msgvec; *ip != NULL; ip++) { + mp = &message[*ip - 1]; + touch(mp); + mp->m_flag |= MDELETED|MTOUCH; + mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); + last = *ip; + } + if (last != NULL) { + dot = &message[last-1]; + last = first(0, MDELETED); + if (last != NULL) { + dot = &message[last-1]; + return(0); + } + else { + dot = &message[0]; + return(-1); + } + } + + /* + * Following can't happen -- it keeps lint happy + */ + + return(-1); +} + +/* + * Undelete the indicated messages. + */ +int +undelete(msgvec) + int *msgvec; +{ + register struct message *mp; + register *ip; + + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + mp->m_flag &= ~MDELETED; + } + return 0; +} + +/* + * Interactively dump core on "core" + */ +int +core() +{ + int pid; + extern union wait wait_status; + + switch (pid = vfork()) { + case -1: + perror("fork"); + return(1); + case 0: + abort(); + _exit(1); + } + printf("Okie dokie"); + fflush(stdout); + wait_child(pid); + if (wait_status.w_coredump) + printf(" -- Core dumped.\n"); + else + printf(" -- Can't dump core.\n"); + return 0; +} + +/* + * Clobber as many bytes of stack as the user requests. + */ +int +clobber(argv) + char **argv; +{ + register int times; + + if (argv[0] == 0) + times = 1; + else + times = (atoi(argv[0]) + 511) / 512; + clob1(times); + return 0; +} + +/* + * Clobber the stack. + */ +void +clob1(n) + int n; +{ + char buf[512]; + register char *cp; + + if (n <= 0) + return; + for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) + ; + clob1(n - 1); +} + +/* + * Add the given header fields to the retained list. + * If no arguments, print the current list of retained fields. + */ +int +retfield(list) + char *list[]; +{ + + return ignore1(list, ignore + 1, "retained"); +} + +/* + * Add the given header fields to the ignored list. + * If no arguments, print the current list of ignored fields. + */ +int +igfield(list) + char *list[]; +{ + + return ignore1(list, ignore, "ignored"); +} + +int +saveretfield(list) + char *list[]; +{ + + return ignore1(list, saveignore + 1, "retained"); +} + +int +saveigfield(list) + char *list[]; +{ + + return ignore1(list, saveignore, "ignored"); +} + +int +ignore1(list, tab, which) + char *list[]; + struct ignoretab *tab; + char *which; +{ + char field[BUFSIZ]; + register int h; + register struct ignore *igp; + char **ap; + + if (*list == NOSTR) + return igshow(tab, which); + for (ap = list; *ap != 0; ap++) { + istrcpy(field, *ap); + if (member(field, tab)) + continue; + h = hash(field); + igp = (struct ignore *) calloc(1, sizeof (struct ignore)); + igp->i_field = calloc((unsigned) strlen(field) + 1, + sizeof (char)); + strcpy(igp->i_field, field); + igp->i_link = tab->i_head[h]; + tab->i_head[h] = igp; + tab->i_count++; + } + return 0; +} + +/* + * Print out all currently retained fields. + */ +int +igshow(tab, which) + struct ignoretab *tab; + char *which; +{ + register int h; + struct ignore *igp; + char **ap, **ring; + int igcomp(); + + if (tab->i_count == 0) { + printf("No fields currently being %s.\n", which); + return 0; + } + ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); + ap = ring; + for (h = 0; h < HSHSIZE; h++) + for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) + *ap++ = igp->i_field; + *ap = 0; + qsort(ring, tab->i_count, sizeof (char *), igcomp); + for (ap = ring; *ap != 0; ap++) + printf("%s\n", *ap); + return 0; +} + +/* + * Compare two names for sorting ignored field list. + */ +int +igcomp(l, r) + const void *l, *r; +{ + return (strcmp(*(char **)l, *(char **)r)); +} diff --git a/usr.bin/mail/cmd3.c b/usr.bin/mail/cmd3.c new file mode 100644 index 0000000..54a5d5e --- /dev/null +++ b/usr.bin/mail/cmd3.c @@ -0,0 +1,730 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd3.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Still more user commands. + */ + +/* + * Process a shell escape by saving signals, ignoring signals, + * and forking a sh -c + */ +int +shell(str) + char *str; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + char *shell; + char cmd[BUFSIZ]; + + (void) strcpy(cmd, str); + if (bangexp(cmd) < 0) + return 1; + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + (void) run_command(shell, 0, -1, -1, "-c", cmd, NOSTR); + (void) signal(SIGINT, sigint); + printf("!\n"); + return 0; +} + +/* + * Fork an interactive shell. + */ +/*ARGSUSED*/ +int +dosh(str) + char *str; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + char *shell; + + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + (void) run_command(shell, 0, -1, -1, NOSTR, NOSTR, NOSTR); + (void) signal(SIGINT, sigint); + putchar('\n'); + return 0; +} + +/* + * Expand the shell escape by expanding unescaped !'s into the + * last issued command where possible. + */ + +char lastbang[128]; + +int +bangexp(str) + char *str; +{ + char bangbuf[BUFSIZ]; + register char *cp, *cp2; + register int n; + int changed = 0; + + cp = str; + cp2 = bangbuf; + n = BUFSIZ; + while (*cp) { + if (*cp == '!') { + if (n < strlen(lastbang)) { +overf: + printf("Command buffer overflow\n"); + return(-1); + } + changed++; + strcpy(cp2, lastbang); + cp2 += strlen(lastbang); + n -= strlen(lastbang); + cp++; + continue; + } + if (*cp == '\\' && cp[1] == '!') { + if (--n <= 1) + goto overf; + *cp2++ = '!'; + cp += 2; + changed++; + } + if (--n <= 1) + goto overf; + *cp2++ = *cp++; + } + *cp2 = 0; + if (changed) { + printf("!%s\n", bangbuf); + fflush(stdout); + } + strcpy(str, bangbuf); + strncpy(lastbang, bangbuf, 128); + lastbang[127] = 0; + return(0); +} + +/* + * Print out a nice help message from some file or another. + */ + +int +help() +{ + register c; + register FILE *f; + + if ((f = Fopen(_PATH_HELP, "r")) == NULL) { + perror(_PATH_HELP); + return(1); + } + while ((c = getc(f)) != EOF) + putchar(c); + Fclose(f); + return(0); +} + +/* + * Change user's working directory. + */ +int +schdir(arglist) + char **arglist; +{ + char *cp; + + if (*arglist == NOSTR) + cp = homedir; + else + if ((cp = expand(*arglist)) == NOSTR) + return(1); + if (chdir(cp) < 0) { + perror(cp); + return(1); + } + return 0; +} + +int +respond(msgvec) + int *msgvec; +{ + if (value("Replyall") == NOSTR) + return (_respond(msgvec)); + else + return (_Respond(msgvec)); +} + +/* + * Reply to a list of messages. Extract each name from the + * message header and send them off to mail1() + */ +int +_respond(msgvec) + int *msgvec; +{ + struct message *mp; + char *cp, *rcv, *replyto; + char **ap; + struct name *np; + struct header head; + + if (msgvec[1] != 0) { + printf("Sorry, can't reply to multiple messages at once\n"); + return(1); + } + mp = &message[msgvec[0] - 1]; + touch(mp); + dot = mp; + if ((rcv = skin(hfield("from", mp))) == NOSTR) + rcv = skin(nameof(mp, 1)); + if ((replyto = skin(hfield("reply-to", mp))) != NOSTR) + np = extract(replyto, GTO); + else if ((cp = skin(hfield("to", mp))) != NOSTR) + np = extract(cp, GTO); + else + np = NIL; + np = elide(np); + /* + * Delete my name from the reply list, + * and with it, all my alternate names. + */ + np = delname(np, myname); + if (altnames) + for (ap = altnames; *ap; ap++) + np = delname(np, *ap); + if (np != NIL && replyto == NOSTR) + np = cat(np, extract(rcv, GTO)); + else if (np == NIL) { + if (replyto != NOSTR) + printf("Empty reply-to field -- replying to author\n"); + np = extract(rcv, GTO); + } + head.h_to = np; + if ((head.h_subject = hfield("subject", mp)) == NOSTR) + head.h_subject = hfield("subj", mp); + head.h_subject = reedit(head.h_subject); + if (replyto == NOSTR && (cp = skin(hfield("cc", mp))) != NOSTR) { + np = elide(extract(cp, GCC)); + np = delname(np, myname); + if (altnames != 0) + for (ap = altnames; *ap; ap++) + np = delname(np, *ap); + head.h_cc = np; + } else + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 1); + return(0); +} + +/* + * Modify the subject we are replying to to begin with Re: if + * it does not already. + */ +char * +reedit(subj) + register char *subj; +{ + char *newsubj; + + if (subj == NOSTR) + return NOSTR; + if ((subj[0] == 'r' || subj[0] == 'R') && + (subj[1] == 'e' || subj[1] == 'E') && + subj[2] == ':') + return subj; + newsubj = salloc(strlen(subj) + 5); + strcpy(newsubj, "Re: "); + strcpy(newsubj + 4, subj); + return newsubj; +} + +/* + * Preserve the named messages, so that they will be sent + * back to the system mailbox. + */ +int +preserve(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, mesg; + + if (edit) { + printf("Cannot \"preserve\" in edit mode\n"); + return(1); + } + for (ip = msgvec; *ip != NULL; ip++) { + mesg = *ip; + mp = &message[mesg-1]; + mp->m_flag |= MPRESERVE; + mp->m_flag &= ~MBOX; + dot = mp; + } + return(0); +} + +/* + * Mark all given messages as unread. + */ +int +unread(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != NULL; ip++) { + dot = &message[*ip-1]; + dot->m_flag &= ~(MREAD|MTOUCH); + dot->m_flag |= MSTATUS; + } + return(0); +} + +/* + * Print the size of each message. + */ +int +messize(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, mesg; + + for (ip = msgvec; *ip != NULL; ip++) { + mesg = *ip; + mp = &message[mesg-1]; + printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size); + } + return(0); +} + +/* + * Quit quickly. If we are sourcing, just pop the input level + * by returning an error. + */ +int +rexit(e) + int e; +{ + if (sourcing) + return(1); + exit(e); + /*NOTREACHED*/ +} + +/* + * Set or display a variable value. Syntax is similar to that + * of csh. + */ +int +set(arglist) + char **arglist; +{ + register struct var *vp; + register char *cp, *cp2; + char varbuf[BUFSIZ], **ap, **p; + int errs, h, s; + + if (*arglist == NOSTR) { + for (h = 0, s = 1; h < HSHSIZE; h++) + for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) + s++; + ap = (char **) salloc(s * sizeof *ap); + for (h = 0, p = ap; h < HSHSIZE; h++) + for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) + *p++ = vp->v_name; + *p = NOSTR; + sort(ap); + for (p = ap; *p != NOSTR; p++) + printf("%s\t%s\n", *p, value(*p)); + return(0); + } + errs = 0; + for (ap = arglist; *ap != NOSTR; ap++) { + cp = *ap; + cp2 = varbuf; + while (*cp != '=' && *cp != '\0') + *cp2++ = *cp++; + *cp2 = '\0'; + if (*cp == '\0') + cp = ""; + else + cp++; + if (equal(varbuf, "")) { + printf("Non-null variable name required\n"); + errs++; + continue; + } + assign(varbuf, cp); + } + return(errs); +} + +/* + * Unset a bunch of variable values. + */ +int +unset(arglist) + char **arglist; +{ + register struct var *vp, *vp2; + int errs, h; + char **ap; + + errs = 0; + for (ap = arglist; *ap != NOSTR; ap++) { + if ((vp2 = lookup(*ap)) == NOVAR) { + if (!sourcing) { + printf("\"%s\": undefined variable\n", *ap); + errs++; + } + continue; + } + h = hash(*ap); + if (vp2 == variables[h]) { + variables[h] = variables[h]->v_link; + vfree(vp2->v_name); + vfree(vp2->v_value); + free((char *)vp2); + continue; + } + for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link) + ; + vp->v_link = vp2->v_link; + vfree(vp2->v_name); + vfree(vp2->v_value); + free((char *) vp2); + } + return(errs); +} + +/* + * Put add users to a group. + */ +int +group(argv) + char **argv; +{ + register struct grouphead *gh; + register struct group *gp; + register int h; + int s; + char **ap, *gname, **p; + + if (*argv == NOSTR) { + for (h = 0, s = 1; h < HSHSIZE; h++) + for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) + s++; + ap = (char **) salloc(s * sizeof *ap); + for (h = 0, p = ap; h < HSHSIZE; h++) + for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) + *p++ = gh->g_name; + *p = NOSTR; + sort(ap); + for (p = ap; *p != NOSTR; p++) + printgroup(*p); + return(0); + } + if (argv[1] == NOSTR) { + printgroup(*argv); + return(0); + } + gname = *argv; + h = hash(gname); + if ((gh = findgroup(gname)) == NOGRP) { + gh = (struct grouphead *) calloc(sizeof *gh, 1); + gh->g_name = vcopy(gname); + gh->g_list = NOGE; + gh->g_link = groups[h]; + groups[h] = gh; + } + + /* + * Insert names from the command list into the group. + * Who cares if there are duplicates? They get tossed + * later anyway. + */ + + for (ap = argv+1; *ap != NOSTR; ap++) { + gp = (struct group *) calloc(sizeof *gp, 1); + gp->ge_name = vcopy(*ap); + gp->ge_link = gh->g_list; + gh->g_list = gp; + } + return(0); +} + +/* + * Sort the passed string vecotor into ascending dictionary + * order. + */ +void +sort(list) + char **list; +{ + register char **ap; + int diction(); + + for (ap = list; *ap != NOSTR; ap++) + ; + if (ap-list < 2) + return; + qsort(list, ap-list, sizeof(*list), diction); +} + +/* + * Do a dictionary order comparison of the arguments from + * qsort. + */ +int +diction(a, b) + const void *a, *b; +{ + return(strcmp(*(char **)a, *(char **)b)); +} + +/* + * The do nothing command for comments. + */ + +/*ARGSUSED*/ +int +null(e) + int e; +{ + return 0; +} + +/* + * Change to another file. With no argument, print information about + * the current file. + */ +int +file(argv) + register char **argv; +{ + + if (argv[0] == NOSTR) { + newfileinfo(); + return 0; + } + if (setfile(*argv) < 0) + return 1; + announce(); + return 0; +} + +/* + * Expand file names like echo + */ +int +echo(argv) + char **argv; +{ + register char **ap; + register char *cp; + + for (ap = argv; *ap != NOSTR; ap++) { + cp = *ap; + if ((cp = expand(cp)) != NOSTR) { + if (ap != argv) + putchar(' '); + printf("%s", cp); + } + } + putchar('\n'); + return 0; +} + +int +Respond(msgvec) + int *msgvec; +{ + if (value("Replyall") == NOSTR) + return (_Respond(msgvec)); + else + return (_respond(msgvec)); +} + +/* + * Reply to a series of messages by simply mailing to the senders + * and not messing around with the To: and Cc: lists as in normal + * reply. + */ +int +_Respond(msgvec) + int msgvec[]; +{ + struct header head; + struct message *mp; + register int *ap; + register char *cp; + + head.h_to = NIL; + for (ap = msgvec; *ap != 0; ap++) { + mp = &message[*ap - 1]; + touch(mp); + dot = mp; + if ((cp = skin(hfield("from", mp))) == NOSTR) + cp = skin(nameof(mp, 2)); + head.h_to = cat(head.h_to, extract(cp, GTO)); + } + if (head.h_to == NIL) + return 0; + mp = &message[msgvec[0] - 1]; + if ((head.h_subject = hfield("subject", mp)) == NOSTR) + head.h_subject = hfield("subj", mp); + head.h_subject = reedit(head.h_subject); + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 1); + return 0; +} + +/* + * Conditional commands. These allow one to parameterize one's + * .mailrc and do some things if sending, others if receiving. + */ +int +ifcmd(argv) + char **argv; +{ + register char *cp; + + if (cond != CANY) { + printf("Illegal nested \"if\"\n"); + return(1); + } + cond = CANY; + cp = argv[0]; + switch (*cp) { + case 'r': case 'R': + cond = CRCV; + break; + + case 's': case 'S': + cond = CSEND; + break; + + default: + printf("Unrecognized if-keyword: \"%s\"\n", cp); + return(1); + } + return(0); +} + +/* + * Implement 'else'. This is pretty simple -- we just + * flip over the conditional flag. + */ +int +elsecmd() +{ + + switch (cond) { + case CANY: + printf("\"Else\" without matching \"if\"\n"); + return(1); + + case CSEND: + cond = CRCV; + break; + + case CRCV: + cond = CSEND; + break; + + default: + printf("Mail's idea of conditions is screwed up\n"); + cond = CANY; + break; + } + return(0); +} + +/* + * End of if statement. Just set cond back to anything. + */ +int +endifcmd() +{ + + if (cond == CANY) { + printf("\"Endif\" without matching \"if\"\n"); + return(1); + } + cond = CANY; + return(0); +} + +/* + * Set the list of alternate names. + */ +int +alternates(namelist) + char **namelist; +{ + register int c; + register char **ap, **ap2, *cp; + + c = argcount(namelist) + 1; + if (c == 1) { + if (altnames == 0) + return(0); + for (ap = altnames; *ap; ap++) + printf("%s ", *ap); + printf("\n"); + return(0); + } + if (altnames != 0) + free((char *) altnames); + altnames = (char **) calloc((unsigned) c, sizeof (char *)); + for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) { + cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char)); + strcpy(cp, *ap); + *ap2 = cp; + } + *ap2 = 0; + return(0); +} diff --git a/usr.bin/mail/cmdtab.c b/usr.bin/mail/cmdtab.c new file mode 100644 index 0000000..94e33a0 --- /dev/null +++ b/usr.bin/mail/cmdtab.c @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "def.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Define all of the command names and bindings. + */ + +struct cmd cmdtab[] = { + "next", next, NDMLIST, 0, MMNDEL, + "alias", group, M|RAWLIST, 0, 1000, + "print", type, MSGLIST, 0, MMNDEL, + "type", type, MSGLIST, 0, MMNDEL, + "Type", Type, MSGLIST, 0, MMNDEL, + "Print", Type, MSGLIST, 0, MMNDEL, + "visual", visual, I|MSGLIST, 0, MMNORM, + "top", top, MSGLIST, 0, MMNDEL, + "touch", stouch, W|MSGLIST, 0, MMNDEL, + "preserve", preserve, W|MSGLIST, 0, MMNDEL, + "delete", delete, W|P|MSGLIST, 0, MMNDEL, + "dp", deltype, W|MSGLIST, 0, MMNDEL, + "dt", deltype, W|MSGLIST, 0, MMNDEL, + "undelete", undelete, P|MSGLIST, MDELETED,MMNDEL, + "unset", unset, M|RAWLIST, 1, 1000, + "mail", sendmail, R|M|I|STRLIST, 0, 0, + "mbox", mboxit, W|MSGLIST, 0, 0, + "more", more, MSGLIST, 0, MMNDEL, + "page", more, MSGLIST, 0, MMNDEL, + "More", More, MSGLIST, 0, MMNDEL, + "Page", More, MSGLIST, 0, MMNDEL, + "unread", unread, MSGLIST, 0, MMNDEL, + "!", shell, I|STRLIST, 0, 0, + "copy", copycmd, M|STRLIST, 0, 0, + "chdir", schdir, M|RAWLIST, 0, 1, + "cd", schdir, M|RAWLIST, 0, 1, + "save", save, STRLIST, 0, 0, + "source", source, M|RAWLIST, 1, 1, + "set", set, M|RAWLIST, 0, 1000, + "shell", dosh, I|NOLIST, 0, 0, + "version", pversion, M|NOLIST, 0, 0, + "group", group, M|RAWLIST, 0, 1000, + "write", swrite, STRLIST, 0, 0, + "from", from, MSGLIST, 0, MMNORM, + "file", file, T|M|RAWLIST, 0, 1, + "folder", file, T|M|RAWLIST, 0, 1, + "folders", folders, T|M|NOLIST, 0, 0, + "?", help, M|NOLIST, 0, 0, + "z", scroll, M|STRLIST, 0, 0, + "headers", headers, MSGLIST, 0, MMNDEL, + "help", help, M|NOLIST, 0, 0, + "=", pdot, NOLIST, 0, 0, + "Reply", Respond, R|I|MSGLIST, 0, MMNDEL, + "Respond", Respond, R|I|MSGLIST, 0, MMNDEL, + "reply", respond, R|I|MSGLIST, 0, MMNDEL, + "respond", respond, R|I|MSGLIST, 0, MMNDEL, + "edit", editor, I|MSGLIST, 0, MMNORM, + "echo", echo, M|RAWLIST, 0, 1000, + "quit", quitcmd, NOLIST, 0, 0, + "list", pcmdlist, M|NOLIST, 0, 0, + "xit", rexit, M|NOLIST, 0, 0, + "exit", rexit, M|NOLIST, 0, 0, + "size", messize, MSGLIST, 0, MMNDEL, + "hold", preserve, W|MSGLIST, 0, MMNDEL, + "if", ifcmd, F|M|RAWLIST, 1, 1, + "else", elsecmd, F|M|RAWLIST, 0, 0, + "endif", endifcmd, F|M|RAWLIST, 0, 0, + "alternates", alternates, M|RAWLIST, 0, 1000, + "ignore", igfield, M|RAWLIST, 0, 1000, + "discard", igfield, M|RAWLIST, 0, 1000, + "retain", retfield, M|RAWLIST, 0, 1000, + "saveignore", saveigfield, M|RAWLIST, 0, 1000, + "savediscard", saveigfield, M|RAWLIST, 0, 1000, + "saveretain", saveretfield, M|RAWLIST, 0, 1000, +/* "Header", Header, STRLIST, 0, 1000, */ + "core", core, M|NOLIST, 0, 0, + "#", null, M|NOLIST, 0, 0, + "clobber", clobber, M|RAWLIST, 0, 1, + 0, 0, 0, 0, 0 +}; diff --git a/usr.bin/mail/collect.c b/usr.bin/mail/collect.c new file mode 100644 index 0000000..9d54fd3 --- /dev/null +++ b/usr.bin/mail/collect.c @@ -0,0 +1,635 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Collect input from standard input, handling + * ~ escapes. + */ + +#include "rcv.h" +#include "extern.h" + +/* + * Read a message from standard output and return a read file to it + * or NULL on error. + */ + +/* + * The following hokiness with global variables is so that on + * receipt of an interrupt signal, the partial message can be salted + * away on dead.letter. + */ + +static sig_t saveint; /* Previous SIGINT value */ +static sig_t savehup; /* Previous SIGHUP value */ +static sig_t savetstp; /* Previous SIGTSTP value */ +static sig_t savettou; /* Previous SIGTTOU value */ +static sig_t savettin; /* Previous SIGTTIN value */ +static FILE *collf; /* File for saving away */ +static int hadintr; /* Have seen one SIGINT so far */ + +static jmp_buf colljmp; /* To get back to work */ +static int colljmp_p; /* whether to long jump */ +static jmp_buf collabort; /* To end collection with error */ + +FILE * +collect(hp, printheaders) + struct header *hp; + int printheaders; +{ + FILE *fbuf; + int lc, cc, escape, eofcount; + register int c, t; + char linebuf[LINESIZE], *cp; + extern char tempMail[]; + char getsub; + int omask; + void collint(), collhup(), collstop(); + + collf = NULL; + /* + * Start catching signals from here, but we're still die on interrupts + * until we're in the main loop. + */ + omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); + if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) + signal(SIGINT, collint); + if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) + signal(SIGHUP, collhup); + savetstp = signal(SIGTSTP, collstop); + savettou = signal(SIGTTOU, collstop); + savettin = signal(SIGTTIN, collstop); + if (setjmp(collabort) || setjmp(colljmp)) { + rm(tempMail); + goto err; + } + sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); + + noreset++; + if ((collf = Fopen(tempMail, "w+")) == NULL) { + perror(tempMail); + goto err; + } + unlink(tempMail); + + /* + * If we are going to prompt for a subject, + * refrain from printing a newline after + * the headers (since some people mind). + */ + t = GTO|GSUBJECT|GCC|GNL; + getsub = 0; + if (hp->h_subject == NOSTR && value("interactive") != NOSTR && + (value("ask") != NOSTR || value("asksub") != NOSTR)) + t &= ~GNL, getsub++; + if (printheaders) { + puthead(hp, stdout, t); + fflush(stdout); + } + if ((cp = value("escape")) != NOSTR) + escape = *cp; + else + escape = ESCAPE; + eofcount = 0; + hadintr = 0; + + if (!setjmp(colljmp)) { + if (getsub) + grabh(hp, GSUBJECT); + } else { + /* + * Come here for printing the after-signal message. + * Duplicate messages won't be printed because + * the write is aborted if we get a SIGTTOU. + */ +cont: + if (hadintr) { + fflush(stdout); + fprintf(stderr, + "\n(Interrupt -- one more to kill letter)\n"); + } else { + printf("(continue)\n"); + fflush(stdout); + } + } + for (;;) { + colljmp_p = 1; + c = readline(stdin, linebuf, LINESIZE); + colljmp_p = 0; + if (c < 0) { + if (value("interactive") != NOSTR && + value("ignoreeof") != NOSTR && ++eofcount < 25) { + printf("Use \".\" to terminate letter\n"); + continue; + } + break; + } + eofcount = 0; + hadintr = 0; + if (linebuf[0] == '.' && linebuf[1] == '\0' && + value("interactive") != NOSTR && + (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) + break; + if (linebuf[0] != escape || value("interactive") == NOSTR) { + if (putline(collf, linebuf) < 0) + goto err; + continue; + } + c = linebuf[1]; + switch (c) { + default: + /* + * On double escape, just send the single one. + * Otherwise, it's an error. + */ + if (c == escape) { + if (putline(collf, &linebuf[1]) < 0) + goto err; + else + break; + } + printf("Unknown tilde escape.\n"); + break; + case 'C': + /* + * Dump core. + */ + core(); + break; + case '!': + /* + * Shell escape, send the balance of the + * line to sh -c. + */ + shell(&linebuf[2]); + break; + case ':': + /* + * Escape to command mode, but be nice! + */ + execute(&linebuf[2], 1); + goto cont; + case '.': + /* + * Simulate end of file on input. + */ + goto out; + case 'q': + /* + * Force a quit of sending mail. + * Act like an interrupt happened. + */ + hadintr++; + collint(SIGINT); + exit(1); + case 'h': + /* + * Grab a bunch of headers. + */ + grabh(hp, GTO|GSUBJECT|GCC|GBCC); + goto cont; + case 't': + /* + * Add to the To list. + */ + hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); + break; + case 's': + /* + * Set the Subject list. + */ + cp = &linebuf[2]; + while (isspace(*cp)) + cp++; + hp->h_subject = savestr(cp); + break; + case 'c': + /* + * Add to the CC list. + */ + hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); + break; + case 'b': + /* + * Add stuff to blind carbon copies list. + */ + hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); + break; + case 'd': + strcpy(linebuf + 2, getdeadletter()); + /* fall into . . . */ + case 'r': + /* + * Invoke a file: + * Search for the file name, + * then open it and copy the contents to collf. + */ + cp = &linebuf[2]; + while (isspace(*cp)) + cp++; + if (*cp == '\0') { + printf("Interpolate what file?\n"); + break; + } + cp = expand(cp); + if (cp == NOSTR) + break; + if (isdir(cp)) { + printf("%s: Directory\n", cp); + break; + } + if ((fbuf = Fopen(cp, "r")) == NULL) { + perror(cp); + break; + } + printf("\"%s\" ", cp); + fflush(stdout); + lc = 0; + cc = 0; + while (readline(fbuf, linebuf, LINESIZE) >= 0) { + lc++; + if ((t = putline(collf, linebuf)) < 0) { + Fclose(fbuf); + goto err; + } + cc += t; + } + Fclose(fbuf); + printf("%d/%d\n", lc, cc); + break; + case 'w': + /* + * Write the message on a file. + */ + cp = &linebuf[2]; + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0') { + fprintf(stderr, "Write what file!?\n"); + break; + } + if ((cp = expand(cp)) == NOSTR) + break; + rewind(collf); + exwrite(cp, collf, 1); + break; + case 'm': + case 'M': + case 'f': + case 'F': + /* + * Interpolate the named messages, if we + * are in receiving mail mode. Does the + * standard list processing garbage. + * If ~f is given, we don't shift over. + */ + if (forward(linebuf + 2, collf, c) < 0) + goto err; + goto cont; + case '?': + if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { + perror(_PATH_TILDE); + break; + } + while ((t = getc(fbuf)) != EOF) + (void) putchar(t); + Fclose(fbuf); + break; + case 'p': + /* + * Print out the current state of the + * message without altering anything. + */ + rewind(collf); + printf("-------\nMessage contains:\n"); + puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); + while ((t = getc(collf)) != EOF) + (void) putchar(t); + goto cont; + case '|': + /* + * Pipe message through command. + * Collect output as new message. + */ + rewind(collf); + mespipe(collf, &linebuf[2]); + goto cont; + case 'v': + case 'e': + /* + * Edit the current message. + * 'e' means to use EDITOR + * 'v' means to use VISUAL + */ + rewind(collf); + mesedit(collf, c); + goto cont; + } + } + goto out; +err: + if (collf != NULL) { + Fclose(collf); + collf = NULL; + } +out: + if (collf != NULL) + rewind(collf); + noreset--; + sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); + signal(SIGINT, saveint); + signal(SIGHUP, savehup); + signal(SIGTSTP, savetstp); + signal(SIGTTOU, savettou); + signal(SIGTTIN, savettin); + sigsetmask(omask); + return collf; +} + +/* + * Write a file, ex-like if f set. + */ +int +exwrite(name, fp, f) + char name[]; + FILE *fp; + int f; +{ + register FILE *of; + register int c; + long cc; + int lc; + struct stat junk; + + if (f) { + printf("\"%s\" ", name); + fflush(stdout); + } + if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) { + if (!f) + fprintf(stderr, "%s: ", name); + fprintf(stderr, "File exists\n"); + return(-1); + } + if ((of = Fopen(name, "w")) == NULL) { + perror(NOSTR); + return(-1); + } + lc = 0; + cc = 0; + while ((c = getc(fp)) != EOF) { + cc++; + if (c == '\n') + lc++; + (void) putc(c, of); + if (ferror(of)) { + perror(name); + Fclose(of); + return(-1); + } + } + Fclose(of); + printf("%d/%ld\n", lc, cc); + fflush(stdout); + return(0); +} + +/* + * Edit the message being collected on fp. + * On return, make the edit file the new temp file. + */ +void +mesedit(fp, c) + FILE *fp; + int c; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + FILE *nf = run_editor(fp, (off_t)-1, c, 0); + + if (nf != NULL) { + fseek(nf, 0L, 2); + collf = nf; + Fclose(fp); + } + (void) signal(SIGINT, sigint); +} + +/* + * Pipe the message through the command. + * Old message is on stdin of command; + * New message collected from stdout. + * Sh -c must return 0 to accept the new message. + */ +void +mespipe(fp, cmd) + FILE *fp; + char cmd[]; +{ + FILE *nf; + sig_t sigint = signal(SIGINT, SIG_IGN); + extern char tempEdit[]; + char *shell; + + if ((nf = Fopen(tempEdit, "w+")) == NULL) { + perror(tempEdit); + goto out; + } + (void) unlink(tempEdit); + /* + * stdin = current message. + * stdout = new message. + */ + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + if (run_command(shell, + 0, fileno(fp), fileno(nf), "-c", cmd, NOSTR) < 0) { + (void) Fclose(nf); + goto out; + } + if (fsize(nf) == 0) { + fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); + (void) Fclose(nf); + goto out; + } + /* + * Take new files. + */ + (void) fseek(nf, 0L, 2); + collf = nf; + (void) Fclose(fp); +out: + (void) signal(SIGINT, sigint); +} + +/* + * Interpolate the named messages into the current + * message, preceding each line with a tab. + * Return a count of the number of characters now in + * the message, or -1 if an error is encountered writing + * the message temporary. The flag argument is 'm' if we + * should shift over and 'f' if not. + */ +int +forward(ms, fp, f) + char ms[]; + FILE *fp; + int f; +{ + register int *msgvec; + extern char tempMail[]; + struct ignoretab *ig; + char *tabst; + + msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); + if (msgvec == (int *) NOSTR) + return(0); + if (getmsglist(ms, msgvec, 0) < 0) + return(0); + if (*msgvec == 0) { + *msgvec = first(0, MMNORM); + if (*msgvec == NULL) { + printf("No appropriate messages\n"); + return(0); + } + msgvec[1] = NULL; + } + if (f == 'f' || f == 'F') + tabst = NOSTR; + else if ((tabst = value("indentprefix")) == NOSTR) + tabst = "\t"; + ig = isupper(f) ? NULL : ignore; + printf("Interpolating:"); + for (; *msgvec != 0; msgvec++) { + struct message *mp = message + *msgvec - 1; + + touch(mp); + printf(" %d", *msgvec); + if (send(mp, fp, ig, tabst) < 0) { + perror(tempMail); + return(-1); + } + } + printf("\n"); + return(0); +} + +/* + * Print (continue) when continued after ^Z. + */ +/*ARGSUSED*/ +void +collstop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + if (colljmp_p) { + colljmp_p = 0; + hadintr = 0; + longjmp(colljmp, 1); + } +} + +/* + * On interrupt, come here to save the partial message in ~/dead.letter. + * Then jump out of the collection loop. + */ +/*ARGSUSED*/ +void +collint(s) + int s; +{ + /* + * the control flow is subtle, because we can be called from ~q. + */ + if (!hadintr) { + if (value("ignore") != NOSTR) { + puts("@"); + fflush(stdout); + clearerr(stdin); + return; + } + hadintr = 1; + longjmp(colljmp, 1); + } + rewind(collf); + if (value("nosave") == NOSTR) + savedeadletter(collf); + longjmp(collabort, 1); +} + +/*ARGSUSED*/ +void +collhup(s) + int s; +{ + rewind(collf); + savedeadletter(collf); + /* + * Let's pretend nobody else wants to clean up, + * a true statement at this time. + */ + exit(1); +} + +void +savedeadletter(fp) + register FILE *fp; +{ + register FILE *dbuf; + register int c; + char *cp; + + if (fsize(fp) == 0) + return; + cp = getdeadletter(); + c = umask(077); + dbuf = Fopen(cp, "a"); + (void) umask(c); + if (dbuf == NULL) + return; + while ((c = getc(fp)) != EOF) + (void) putc(c, dbuf); + Fclose(dbuf); + rewind(fp); +} diff --git a/usr.bin/mail/def.h b/usr.bin/mail/def.h new file mode 100644 index 0000000..f843914 --- /dev/null +++ b/usr.bin/mail/def.h @@ -0,0 +1,276 @@ +/* + * 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. + * + * @(#)def.h 8.2 (Berkeley) 3/21/94 + */ + +/* + * Mail -- a mail program + * + * Author: Kurt Shoens (UCB) March 25, 1978 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +#define APPEND /* New mail goes to end of mailbox */ + +#define ESCAPE '~' /* Default escape for sending */ +#define NMLSIZE 1024 /* max names in a message list */ +#define PATHSIZE MAXPATHLEN /* Size of pathnames throughout */ +#define HSHSIZE 59 /* Hash size for aliases and vars */ +#define LINESIZE BUFSIZ /* max readable line width */ +#define STRINGSIZE ((unsigned) 128)/* Dynamic allocation units */ +#define MAXARGC 1024 /* Maximum list of raw strings */ +#define NOSTR ((char *) 0) /* Null string pointer */ +#define MAXEXP 25 /* Maximum expansion of aliases */ + +#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */ + +struct message { + short m_flag; /* flags, see below */ + short m_block; /* block number of this message */ + short m_offset; /* offset in block of message */ + long m_size; /* Bytes in the message */ + short m_lines; /* Lines in the message */ +}; + +/* + * flag bits. + */ + +#define MUSED (1<<0) /* entry is used, but this bit isn't */ +#define MDELETED (1<<1) /* entry has been deleted */ +#define MSAVED (1<<2) /* entry has been saved */ +#define MTOUCH (1<<3) /* entry has been noticed */ +#define MPRESERVE (1<<4) /* keep entry in sys mailbox */ +#define MMARK (1<<5) /* message is marked! */ +#define MODIFY (1<<6) /* message has been modified */ +#define MNEW (1<<7) /* message has never been seen */ +#define MREAD (1<<8) /* message has been read sometime. */ +#define MSTATUS (1<<9) /* message status has changed */ +#define MBOX (1<<10) /* Send this to mbox, regardless */ + +/* + * Given a file address, determine the block number it represents. + */ +#define blockof(off) ((int) ((off) / 4096)) +#define offsetof(off) ((int) ((off) % 4096)) +#define positionof(block, offset) ((off_t)(block) * 4096 + (offset)) + +/* + * Format of the command description table. + * The actual table is declared and initialized + * in lex.c + */ +struct cmd { + char *c_name; /* Name of command */ + int (*c_func)(); /* Implementor of the command */ + short c_argtype; /* Type of arglist (see below) */ + short c_msgflag; /* Required flags of messages */ + short c_msgmask; /* Relevant flags of messages */ +}; + +/* Yechh, can't initialize unions */ + +#define c_minargs c_msgflag /* Minimum argcount for RAWLIST */ +#define c_maxargs c_msgmask /* Max argcount for RAWLIST */ + +/* + * Argument types. + */ + +#define MSGLIST 0 /* Message list type */ +#define STRLIST 1 /* A pure string */ +#define RAWLIST 2 /* Shell string list */ +#define NOLIST 3 /* Just plain 0 */ +#define NDMLIST 4 /* Message list, no defaults */ + +#define P 040 /* Autoprint dot after command */ +#define I 0100 /* Interactive command bit */ +#define M 0200 /* Legal from send mode bit */ +#define W 0400 /* Illegal when read only bit */ +#define F 01000 /* Is a conditional command */ +#define T 02000 /* Is a transparent command */ +#define R 04000 /* Cannot be called from collect */ + +/* + * Oft-used mask values + */ + +#define MMNORM (MDELETED|MSAVED)/* Look at both save and delete bits */ +#define MMNDEL MDELETED /* Look only at deleted bit */ + +/* + * Structure used to return a break down of a head + * line (hats off to Bill Joy!) + */ + +struct headline { + char *l_from; /* The name of the sender */ + char *l_tty; /* His tty string (if any) */ + char *l_date; /* The entire date string */ +}; + +#define GTO 1 /* Grab To: line */ +#define GSUBJECT 2 /* Likewise, Subject: line */ +#define GCC 4 /* And the Cc: line */ +#define GBCC 8 /* And also the Bcc: line */ +#define GMASK (GTO|GSUBJECT|GCC|GBCC) + /* Mask of places from whence */ + +#define GNL 16 /* Print blank line after */ +#define GDEL 32 /* Entity removed from list */ +#define GCOMMA 64 /* detract puts in commas */ + +/* + * Structure used to pass about the current + * state of the user-typed message header. + */ + +struct header { + struct name *h_to; /* Dynamic "To:" string */ + char *h_subject; /* Subject string */ + struct name *h_cc; /* Carbon copies string */ + struct name *h_bcc; /* Blind carbon copies */ + struct name *h_smopts; /* Sendmail options */ +}; + +/* + * Structure of namelist nodes used in processing + * the recipients of mail and aliases and all that + * kind of stuff. + */ + +struct name { + struct name *n_flink; /* Forward link in list. */ + struct name *n_blink; /* Backward list link */ + short n_type; /* From which list it came */ + char *n_name; /* This fella's name */ +}; + +/* + * Structure of a variable node. All variables are + * kept on a singly-linked list of these, rooted by + * "variables" + */ + +struct var { + struct var *v_link; /* Forward link to next variable */ + char *v_name; /* The variable's name */ + char *v_value; /* And it's current value */ +}; + +struct group { + struct group *ge_link; /* Next person in this group */ + char *ge_name; /* This person's user name */ +}; + +struct grouphead { + struct grouphead *g_link; /* Next grouphead in list */ + char *g_name; /* Name of this group */ + struct group *g_list; /* Users in group. */ +}; + +#define NIL ((struct name *) 0) /* The nil pointer for namelists */ +#define NONE ((struct cmd *) 0) /* The nil pointer to command tab */ +#define NOVAR ((struct var *) 0) /* The nil pointer to variables */ +#define NOGRP ((struct grouphead *) 0)/* The nil grouphead pointer */ +#define NOGE ((struct group *) 0) /* The nil group pointer */ + +/* + * Structure of the hash table of ignored header fields + */ +struct ignoretab { + int i_count; /* Number of entries */ + struct ignore { + struct ignore *i_link; /* Next ignored field in bucket */ + char *i_field; /* This ignored field */ + } *i_head[HSHSIZE]; +}; + +/* + * Token values returned by the scanner used for argument lists. + * Also, sizes of scanner-related things. + */ + +#define TEOL 0 /* End of the command line */ +#define TNUMBER 1 /* A message number */ +#define TDASH 2 /* A simple dash */ +#define TSTRING 3 /* A string (possibly containing -) */ +#define TDOT 4 /* A "." */ +#define TUP 5 /* An "^" */ +#define TDOLLAR 6 /* A "$" */ +#define TSTAR 7 /* A "*" */ +#define TOPEN 8 /* An '(' */ +#define TCLOSE 9 /* A ')' */ +#define TPLUS 10 /* A '+' */ +#define TERROR 11 /* A lexical error */ + +#define REGDEP 2 /* Maximum regret depth. */ +#define STRINGLEN 1024 /* Maximum length of string token */ + +/* + * Constants for conditional commands. These describe whether + * we should be executing stuff or not. + */ + +#define CANY 0 /* Execute in send or receive mode */ +#define CRCV 1 /* Execute in receive mode only */ +#define CSEND 2 /* Execute in send mode only */ + +/* + * Kludges to handle the change from setexit / reset to setjmp / longjmp + */ + +#define setexit() setjmp(srbuf) +#define reset(x) longjmp(srbuf, x) + +/* + * Truncate a file to the last character written. This is + * useful just before closing an old file that was opened + * for read/write. + */ +#define trunc(stream) { \ + (void)fflush(stream); \ + (void)ftruncate(fileno(stream), (long)ftell(stream)); \ +} diff --git a/usr.bin/mail/edit.c b/usr.bin/mail/edit.c new file mode 100644 index 0000000..97d3bd4 --- /dev/null +++ b/usr.bin/mail/edit.c @@ -0,0 +1,220 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * Perform message editing functions. + */ + +/* + * Edit a message list. + */ +int +editor(msgvec) + int *msgvec; +{ + + return edit1(msgvec, 'e'); +} + +/* + * Invoke the visual editor on a message list. + */ +int +visual(msgvec) + int *msgvec; +{ + + return edit1(msgvec, 'v'); +} + +/* + * Edit a message by writing the message into a funnily-named file + * (which should not exist) and forking an editor on it. + * We get the editor from the stuff above. + */ +int +edit1(msgvec, type) + int *msgvec; + int type; +{ + register int c; + int i; + FILE *fp; + register struct message *mp; + off_t size; + + /* + * Deal with each message to be edited . . . + */ + for (i = 0; msgvec[i] && i < msgCount; i++) { + sig_t sigint; + + if (i > 0) { + char buf[100]; + char *p; + + printf("Edit message %d [ynq]? ", msgvec[i]); + if (fgets(buf, sizeof buf, stdin) == 0) + break; + for (p = buf; *p == ' ' || *p == '\t'; p++) + ; + if (*p == 'q') + break; + if (*p == 'n') + continue; + } + dot = mp = &message[msgvec[i] - 1]; + touch(mp); + sigint = signal(SIGINT, SIG_IGN); + fp = run_editor(setinput(mp), mp->m_size, type, readonly); + if (fp != NULL) { + (void) fseek(otf, 0L, 2); + size = ftell(otf); + mp->m_block = blockof(size); + mp->m_offset = offsetof(size); + mp->m_size = fsize(fp); + mp->m_lines = 0; + mp->m_flag |= MODIFY; + rewind(fp); + while ((c = getc(fp)) != EOF) { + if (c == '\n') + mp->m_lines++; + if (putc(c, otf) == EOF) + break; + } + if (ferror(otf)) + perror("/tmp"); + (void) Fclose(fp); + } + (void) signal(SIGINT, sigint); + } + return 0; +} + +/* + * Run an editor on the file at "fpp" of "size" bytes, + * and return a new file pointer. + * Signals must be handled by the caller. + * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. + */ +FILE * +run_editor(fp, size, type, readonly) + register FILE *fp; + off_t size; + int type, readonly; +{ + register FILE *nf = NULL; + register int t; + time_t modtime; + char *edit; + struct stat statb; + extern char tempEdit[]; + + if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) { + perror(tempEdit); + goto out; + } + if ((nf = Fdopen(t, "w")) == NULL) { + perror(tempEdit); + (void) unlink(tempEdit); + goto out; + } + if (size >= 0) + while (--size >= 0 && (t = getc(fp)) != EOF) + (void) putc(t, nf); + else + while ((t = getc(fp)) != EOF) + (void) putc(t, nf); + (void) fflush(nf); + if (fstat(fileno(nf), &statb) < 0) + modtime = 0; + else + modtime = statb.st_mtime; + if (ferror(nf)) { + (void) Fclose(nf); + perror(tempEdit); + (void) unlink(tempEdit); + nf = NULL; + goto out; + } + if (Fclose(nf) < 0) { + perror(tempEdit); + (void) unlink(tempEdit); + nf = NULL; + goto out; + } + nf = NULL; + if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) + edit = type == 'e' ? _PATH_EX : _PATH_VI; + if (run_command(edit, 0, -1, -1, tempEdit, NOSTR, NOSTR) < 0) { + (void) unlink(tempEdit); + goto out; + } + /* + * If in read only mode or file unchanged, just remove the editor + * temporary and return. + */ + if (readonly) { + (void) unlink(tempEdit); + goto out; + } + if (stat(tempEdit, &statb) < 0) { + perror(tempEdit); + goto out; + } + if (modtime == statb.st_mtime) { + (void) unlink(tempEdit); + goto out; + } + /* + * Now switch to new file. + */ + if ((nf = Fopen(tempEdit, "a+")) == NULL) { + perror(tempEdit); + (void) unlink(tempEdit); + goto out; + } + (void) unlink(tempEdit); +out: + return nf; +} diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h new file mode 100644 index 0000000..8b1babf --- /dev/null +++ b/usr.bin/mail/extern.h @@ -0,0 +1,253 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +struct name *cat __P((struct name *, struct name *)); +struct name *delname __P((struct name *, char [])); +struct name *elide __P((struct name *)); +struct name *extract __P((char [], int)); +struct name *gexpand __P((struct name *, struct grouphead *, int, int)); +struct name *nalloc __P((char [], int)); +struct name *outof __P((struct name *, FILE *, struct header *)); +struct name *put __P((struct name *, struct name *)); +struct name *tailof __P((struct name *)); +struct name *usermap __P((struct name *)); +FILE *Fdopen __P((int, char *)); +FILE *Fopen __P((char *, char *)); +FILE *Popen __P((char *, char *)); +FILE *collect __P((struct header *, int)); +char *copy __P((char *, char *)); +char *copyin __P((char *, char **)); +char *detract __P((struct name *, int)); +char *expand __P((char *)); +char *getdeadletter __P((void)); +char *getname __P((int)); +char *hfield __P((char [], struct message *)); +FILE *infix __P((struct header *, FILE *)); +char *ishfield __P((char [], char[], char *)); +char *name1 __P((struct message *, int)); +char *nameof __P((struct message *, int)); +char *nextword __P((char *, char *)); +char *readtty __P((char [], char [])); +char *reedit __P((char *)); +FILE *run_editor __P((FILE *, off_t, int, int)); +char *salloc __P((int)); +char *savestr __P((char *)); +FILE *setinput __P((struct message *)); +char *skin __P((char *)); +char *skip_comment __P((char *)); +char *snarf __P((char [], int *)); +char *username __P((void)); +char *value __P((char [])); +char *vcopy __P((char [])); +char *yankword __P((char *, char [])); +int Fclose __P((FILE *)); +int More __P((int *)); +int Pclose __P((FILE *)); +int Respond __P((int *)); +int Type __P((int *)); +int _Respond __P((int [])); +int _respond __P((int *)); +void alter __P((char *)); +int alternates __P((char **)); +void announce __P((void)); +int anyof __P((char *, char *)); +int append __P((struct message *, FILE *)); +int argcount __P((char **)); +void assign __P((char [], char [])); +int bangexp __P((char *)); +int blankline __P((char [])); +void brokpipe __P((int)); +int charcount __P((char *, int)); +int check __P((int, int)); +void clob1 __P((int)); +int clobber __P((char **)); +void close_all_files __P((void)); +int cmatch __P((char *, char *)); +void collhup __P((int)); +void collint __P((int)); +void collstop __P((int)); +void commands __P((void)); +int copycmd __P((char [])); +int core __P((void)); +int count __P((struct name *)); +int delete __P((int [])); +int delm __P((int [])); +int deltype __P((int [])); +void demail __P((void)); +int diction __P((const void *, const void *)); +int dosh __P((char *)); +int echo __P((char **)); +int edit1 __P((int *, int)); +int editor __P((int *)); +void edstop __P((void)); +int elsecmd __P((void)); +int endifcmd __P((void)); +int evalcol __P((int)); +int execute __P((char [], int)); +int exwrite __P((char [], FILE *, int)); +void fail __P((char [], char [])); +int file __P((char **)); +struct grouphead * + findgroup __P((char [])); +void findmail __P((char *, char *)); +int first __P((int, int)); +void fixhead __P((struct header *, struct name *)); +void fmt __P((char *, struct name *, FILE *, int)); +int folders __P((void)); +int forward __P((char [], FILE *, int)); +void free_child __P((int)); +int from __P((int *)); +off_t fsize __P((FILE *)); +int getfold __P((char *)); +int gethfield __P((FILE *, char [], int, char **)); +int getmsglist __P((char *, int *, int)); +int getrawlist __P((char [], char **, int)); +int getuserid __P((char [])); +int grabh __P((struct header *, int)); +int group __P((char **)); +void hangup __P((int)); +int hash __P((char *)); +void hdrstop __P((int)); +int headers __P((int *)); +int help __P((void)); +void holdsigs __P((void)); +int ifcmd __P((char **)); +int igcomp __P((const void *, const void *)); +int igfield __P((char *[])); +int ignore1 __P((char *[], struct ignoretab *, char *)); +int igshow __P((struct ignoretab *, char *)); +void intr __P((int)); +int isdate __P((char [])); +int isdir __P((char [])); +int isfileaddr __P((char *)); +int ishead __P((char [])); +int isign __P((char *, struct ignoretab [])); +int isprefix __P((char *, char *)); +void istrcpy __P((char *, char *)); +struct cmd * + lex __P((char [])); +void load __P((char *)); +struct var * + lookup __P((char [])); +int mail __P((struct name *, + struct name *, struct name *, struct name *, char *)); +void mail1 __P((struct header *, int)); +void makemessage __P((FILE *)); +void mark __P((int)); +int markall __P((char [], int)); +int matchsender __P((char *, int)); +int matchsubj __P((char *, int)); +int mboxit __P((int [])); +int member __P((char *, struct ignoretab *)); +void mesedit __P((FILE *, int)); +void mespipe __P((FILE *, char [])); +int messize __P((int *)); +int metamess __P((int, int)); +int more __P((int *)); +int newfileinfo __P((void)); +int next __P((int *)); +int null __P((int)); +void panic __P((const char *, ...)); +void parse __P((char [], struct headline *, char [])); +int pcmdlist __P((void)); +int pdot __P((void)); +void prepare_child __P((int, int, int)); +int preserve __P((int *)); +void prettyprint __P((struct name *)); +void printgroup __P((char [])); +void printhead __P((int)); +int puthead __P((struct header *, FILE *, int)); +int putline __P((FILE *, char *)); +int pversion __P((int)); +void quit __P((void)); +int quitcmd __P((void)); +int raise __P((int)); +int readline __P((FILE *, char *, int)); +void register_file __P((FILE *, int, int)); +void regret __P((int)); +void relsesigs __P((void)); +int respond __P((int *)); +int retfield __P((char *[])); +int rexit __P((int)); +int rm __P((char *)); +int run_command __P((char *, int, int, int, char *, char *, char *)); +int save __P((char [])); +int save1 __P((char [], int, char *, struct ignoretab *)); +void savedeadletter __P((FILE *)); +int saveigfield __P((char *[])); +int savemail __P((char [], FILE *)); +int saveretfield __P((char *[])); +int scan __P((char **)); +void scaninit __P((void)); +int schdir __P((char **)); +int screensize __P((void)); +int scroll __P((char [])); +int send __P((struct message *, FILE *, struct ignoretab *, char *)); +int sendmail __P((char *)); +int set __P((char **)); +int setfile __P((char *)); +void setmsize __P((int)); +void setptr __P((FILE *)); +void setscreensize __P((void)); +int shell __P((char *)); +void sigchild __P((int)); +void sort __P((char **)); +int source __P((char **)); +void spreserve __P((void)); +void sreset __P((void)); +int start_command __P((char *, int, int, int, char *, char *, char *)); +void statusput __P((struct message *, FILE *, char *)); +void stop __P((int)); +int stouch __P((int [])); +int swrite __P((char [])); +void tinit __P((void)); +int top __P((int *)); +void touch __P((struct message *)); +void ttyint __P((int)); +void ttystop __P((int)); +int type __P((int *)); +int type1 __P((int *, int, int)); +int undelete __P((int *)); +void unmark __P((int)); +char **unpack __P((struct name *)); +int unread __P((int [])); +void unregister_file __P((FILE *)); +int unset __P((char **)); +int unstack __P((void)); +void vfree __P((char *)); +int visual __P((int *)); +int wait_child __P((int)); +int wait_command __P((int)); +int writeback __P((FILE *)); diff --git a/usr.bin/mail/fio.c b/usr.bin/mail/fio.c new file mode 100644 index 0000000..4f2a8a8 --- /dev/null +++ b/usr.bin/mail/fio.c @@ -0,0 +1,431 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)fio.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include + +#include +#include +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * File I/O. + */ + +/* + * Set up the input pointers while copying the mail file into /tmp. + */ +void +setptr(ibuf) + register FILE *ibuf; +{ + extern char *tmpdir; + register int c, count; + register char *cp, *cp2; + struct message this; + FILE *mestmp; + off_t offset; + int maybe, inhead; + char linebuf[LINESIZE]; + + /* Get temporary file. */ + (void)sprintf(linebuf, "%s/mail.XXXXXX", tmpdir); + if ((c = mkstemp(linebuf)) == -1 || + (mestmp = Fdopen(c, "r+")) == NULL) { + (void)fprintf(stderr, "mail: can't open %s\n", linebuf); + exit(1); + } + (void)unlink(linebuf); + + msgCount = 0; + maybe = 1; + inhead = 0; + offset = 0; + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = 0; + this.m_offset = 0; + for (;;) { + if (fgets(linebuf, LINESIZE, ibuf) == NULL) { + if (append(&this, mestmp)) { + perror("temporary file"); + exit(1); + } + makemessage(mestmp); + return; + } + count = strlen(linebuf); + (void) fwrite(linebuf, sizeof *linebuf, count, otf); + if (ferror(otf)) { + perror("/tmp"); + exit(1); + } + linebuf[count - 1] = 0; + if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { + msgCount++; + if (append(&this, mestmp)) { + perror("temporary file"); + exit(1); + } + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = blockof(offset); + this.m_offset = offsetof(offset); + inhead = 1; + } else if (linebuf[0] == 0) { + inhead = 0; + } else if (inhead) { + for (cp = linebuf, cp2 = "status";; cp++) { + if ((c = *cp2++) == 0) { + while (isspace(*cp++)) + ; + if (cp[-1] != ':') + break; + while (c = *cp++) + if (c == 'R') + this.m_flag |= MREAD; + else if (c == 'O') + this.m_flag &= ~MNEW; + inhead = 0; + break; + } + if (*cp != c && *cp != toupper(c)) + break; + } + } + offset += count; + this.m_size += count; + this.m_lines++; + maybe = linebuf[0] == 0; + } +} + +/* + * Drop the passed line onto the passed output buffer. + * If a write error occurs, return -1, else the count of + * characters written, including the newline. + */ +int +putline(obuf, linebuf) + FILE *obuf; + char *linebuf; +{ + register int c; + + c = strlen(linebuf); + (void) fwrite(linebuf, sizeof *linebuf, c, obuf); + (void) putc('\n', obuf); + if (ferror(obuf)) + return (-1); + return (c + 1); +} + +/* + * Read up a line from the specified input into the line + * buffer. Return the number of characters read. Do not + * include the newline at the end. + */ +int +readline(ibuf, linebuf, linesize) + FILE *ibuf; + char *linebuf; + int linesize; +{ + register int n; + + clearerr(ibuf); + if (fgets(linebuf, linesize, ibuf) == NULL) + return -1; + n = strlen(linebuf); + if (n > 0 && linebuf[n - 1] == '\n') + linebuf[--n] = '\0'; + return n; +} + +/* + * Return a file buffer all ready to read up the + * passed message pointer. + */ +FILE * +setinput(mp) + register struct message *mp; +{ + + fflush(otf); + if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) { + perror("fseek"); + panic("temporary file seek"); + } + return (itf); +} + +/* + * Take the data out of the passed ghost file and toss it into + * a dynamically allocated message structure. + */ +void +makemessage(f) + FILE *f; +{ + register size = (msgCount + 1) * sizeof (struct message); + + if (message != 0) + free((char *) message); + if ((message = (struct message *) malloc((unsigned) size)) == 0) + panic("Insufficient memory for %d messages", msgCount); + dot = message; + size -= sizeof (struct message); + fflush(f); + (void) lseek(fileno(f), (off_t)sizeof *message, 0); + if (read(fileno(f), (char *) message, size) != size) + panic("Message temporary file corrupted"); + message[msgCount].m_size = 0; + message[msgCount].m_lines = 0; + Fclose(f); +} + +/* + * Append the passed message descriptor onto the temp file. + * If the write fails, return 1, else 0 + */ +int +append(mp, f) + struct message *mp; + FILE *f; +{ + return fwrite((char *) mp, sizeof *mp, 1, f) != 1; +} + +/* + * Delete a file, but only if the file is a plain file. + */ +int +rm(name) + char *name; +{ + struct stat sb; + + if (stat(name, &sb) < 0) + return(-1); + if (!S_ISREG(sb.st_mode)) { + errno = EISDIR; + return(-1); + } + return(unlink(name)); +} + +static int sigdepth; /* depth of holdsigs() */ +static int omask; +/* + * Hold signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +holdsigs() +{ + + if (sigdepth++ == 0) + omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)); +} + +/* + * Release signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +relsesigs() +{ + + if (--sigdepth == 0) + sigsetmask(omask); +} + +/* + * Determine the size of the file possessed by + * the passed buffer. + */ +off_t +fsize(iob) + FILE *iob; +{ + struct stat sbuf; + + if (fstat(fileno(iob), &sbuf) < 0) + return 0; + return sbuf.st_size; +} + +/* + * Evaluate the string given as a new mailbox name. + * Supported meta characters: + * % for my system mail box + * %user for user's system mail box + * # for previous file + * & invoker's mbox file + * +file file in folder directory + * any shell meta character + * Return the file name as a dynamic string. + */ +char * +expand(name) + register char *name; +{ + char xname[PATHSIZE]; + char cmdbuf[PATHSIZE]; /* also used for file names */ + register int pid, l; + register char *cp, *shell; + int pivec[2]; + struct stat sbuf; + extern union wait wait_status; + + /* + * The order of evaluation is "%" and "#" expand into constants. + * "&" can expand into "+". "+" can expand into shell meta characters. + * Shell meta characters expand into constants. + * This way, we make no recursive expansion. + */ + switch (*name) { + case '%': + findmail(name[1] ? name + 1 : myname, xname); + return savestr(xname); + case '#': + if (name[1] != 0) + break; + if (prevfile[0] == 0) { + printf("No previous file\n"); + return NOSTR; + } + return savestr(prevfile); + case '&': + if (name[1] == 0 && (name = value("MBOX")) == NOSTR) + name = "~/mbox"; + /* fall through */ + } + if (name[0] == '+' && getfold(cmdbuf) >= 0) { + sprintf(xname, "%s/%s", cmdbuf, name + 1); + name = savestr(xname); + } + /* catch the most common shell meta character */ + if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) { + sprintf(xname, "%s%s", homedir, name + 1); + name = savestr(xname); + } + if (!anyof(name, "~{[*?$`'\"\\")) + return name; + if (pipe(pivec) < 0) { + perror("pipe"); + return name; + } + sprintf(cmdbuf, "echo %s", name); + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR); + if (pid < 0) { + close(pivec[0]); + close(pivec[1]); + return NOSTR; + } + close(pivec[1]); + l = read(pivec[0], xname, BUFSIZ); + close(pivec[0]); + if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) { + fprintf(stderr, "\"%s\": Expansion failed.\n", name); + return NOSTR; + } + if (l < 0) { + perror("read"); + return NOSTR; + } + if (l == 0) { + fprintf(stderr, "\"%s\": No match.\n", name); + return NOSTR; + } + if (l == BUFSIZ) { + fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); + return NOSTR; + } + xname[l] = 0; + for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) + ; + cp[1] = '\0'; + if (index(xname, ' ') && stat(xname, &sbuf) < 0) { + fprintf(stderr, "\"%s\": Ambiguous.\n", name); + return NOSTR; + } + return savestr(xname); +} + +/* + * Determine the current folder directory name. + */ +int +getfold(name) + char *name; +{ + char *folder; + + if ((folder = value("folder")) == NOSTR) + return (-1); + if (*folder == '/') + strcpy(name, folder); + else + sprintf(name, "%s/%s", homedir, folder); + return (0); +} + +/* + * Return the name of the dead.letter file. + */ +char * +getdeadletter() +{ + register char *cp; + + if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR) + cp = expand("~/dead.letter"); + else if (*cp != '/') { + char buf[PATHSIZE]; + + (void) sprintf(buf, "~/%s", cp); + cp = expand(buf); + } + return cp; +} diff --git a/usr.bin/mail/getname.c b/usr.bin/mail/getname.c new file mode 100644 index 0000000..02a4131 --- /dev/null +++ b/usr.bin/mail/getname.c @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)getname.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* Getname / getuserid for those with hashed passwd data base). */ + +/* + * Search the passwd file for a uid. Return name through ref parameter + * if found, indicating success with 0 return. Return -1 on error. + */ +char * +getname(uid) + int uid; +{ + struct passwd *pw; + + if ((pw = getpwuid(uid)) == NULL) + return NOSTR; + return pw->pw_name; +} + +/* + * Convert the passed name to a user id and return it. Return -1 + * on error. + */ +int +getuserid(name) + char name[]; +{ + struct passwd *pw; + + if ((pw = getpwnam(name)) == NULL) + return -1; + return pw->pw_uid; +} diff --git a/usr.bin/mail/glob.h b/usr.bin/mail/glob.h new file mode 100644 index 0000000..a159aca --- /dev/null +++ b/usr.bin/mail/glob.h @@ -0,0 +1,100 @@ +/* + * 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. + * + * @(#)glob.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * A bunch of global variable declarations lie herein. + * def.h must be included first. + */ + +int msgCount; /* Count of messages read in */ +int rcvmode; /* True if receiving mail */ +int sawcom; /* Set after first command */ +char *Tflag; /* -T temp file for netnews */ +int senderr; /* An error while checking */ +int edit; /* Indicates editing a file */ +int readonly; /* Will be unable to rewrite file */ +int noreset; /* String resets suspended */ +int sourcing; /* Currently reading variant file */ +int loading; /* Loading user definitions */ +int cond; /* Current state of conditional exc. */ +FILE *itf; /* Input temp file buffer */ +FILE *otf; /* Output temp file buffer */ +int image; /* File descriptor for image of msg */ +FILE *input; /* Current command input file */ +char mailname[PATHSIZE]; /* Name of current file */ +char prevfile[PATHSIZE]; /* Name of previous file */ +char *homedir; /* Path name of home directory */ +char *myname; /* My login name */ +off_t mailsize; /* Size of system mailbox */ +int lexnumber; /* Number of TNUMBER from scan() */ +char lexstring[STRINGLEN]; /* String from TSTRING, scan() */ +int regretp; /* Pointer to TOS of regret tokens */ +int regretstack[REGDEP]; /* Stack of regretted tokens */ +char *string_stack[REGDEP]; /* Stack of regretted strings */ +int numberstack[REGDEP]; /* Stack of regretted numbers */ +struct message *dot; /* Pointer to current message */ +struct message *message; /* The actual message structure */ +struct var *variables[HSHSIZE]; /* Pointer to active var list */ +struct grouphead *groups[HSHSIZE];/* Pointer to active groups */ +struct ignoretab ignore[2]; /* ignored and retained fields + 0 is ignore, 1 is retain */ +struct ignoretab saveignore[2]; /* ignored and retained fields + on save to folder */ +struct ignoretab ignoreall[2]; /* special, ignore all headers */ +char **altnames; /* List of alternate names for user */ +int debug; /* Debug flag set */ +int screenwidth; /* Screen width, or best guess */ +int screenheight; /* Screen height, or best guess, + for "header" command */ +int realscreenheight; /* the real screen height */ + +#include + +jmp_buf srbuf; + + +/* + * The pointers for the string allocation routines, + * there are NSPACE independent areas. + * The first holds STRINGSIZE bytes, the next + * twice as much, and so on. + */ + +#define NSPACE 25 /* Total number of string spaces */ +struct strings { + char *s_topFree; /* Beginning of this area */ + char *s_nextFree; /* Next alloctable place here */ + unsigned s_nleft; /* Number of bytes left here */ +} stringdope[NSPACE]; diff --git a/usr.bin/mail/head.c b/usr.bin/mail/head.c new file mode 100644 index 0000000..ca31ae1 --- /dev/null +++ b/usr.bin/mail/head.c @@ -0,0 +1,254 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)head.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Routines for processing and detecting headlines. + */ + +/* + * See if the passed line buffer is a mail header. + * Return true if yes. Note the extreme pains to + * accomodate all funny formats. + */ +int +ishead(linebuf) + char linebuf[]; +{ + register char *cp; + struct headline hl; + char parbuf[BUFSIZ]; + + cp = linebuf; + if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || + *cp++ != ' ') + return (0); + parse(linebuf, &hl, parbuf); + if (hl.l_from == NOSTR || hl.l_date == NOSTR) { + fail(linebuf, "No from or date field"); + return (0); + } + if (!isdate(hl.l_date)) { + fail(linebuf, "Date field not legal date"); + return (0); + } + /* + * I guess we got it! + */ + return (1); +} + +/*ARGSUSED*/ +void +fail(linebuf, reason) + char linebuf[], reason[]; +{ + + /* + if (value("debug") == NOSTR) + return; + fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); + */ +} + +/* + * Split a headline into its useful components. + * Copy the line into dynamic string space, then set + * pointers into the copied line in the passed headline + * structure. Actually, it scans. + */ +void +parse(line, hl, pbuf) + char line[], pbuf[]; + register struct headline *hl; +{ + register char *cp; + char *sp; + char word[LINESIZE]; + + hl->l_from = NOSTR; + hl->l_tty = NOSTR; + hl->l_date = NOSTR; + cp = line; + sp = pbuf; + /* + * Skip over "From" first. + */ + cp = nextword(cp, word); + cp = nextword(cp, word); + if (*word) + hl->l_from = copyin(word, &sp); + if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { + cp = nextword(cp, word); + hl->l_tty = copyin(word, &sp); + } + if (cp != NOSTR) + hl->l_date = copyin(cp, &sp); +} + +/* + * Copy the string on the left into the string on the right + * and bump the right (reference) string pointer by the length. + * Thus, dynamically allocate space in the right string, copying + * the left string into it. + */ +char * +copyin(src, space) + register char *src; + char **space; +{ + register char *cp; + char *top; + + top = cp = *space; + while (*cp++ = *src++) + ; + *space = cp; + return (top); +} + +/* + * Test to see if the passed string is a ctime(3) generated + * date string as documented in the manual. The template + * below is used as the criterion of correctness. + * Also, we check for a possible trailing time zone using + * the tmztype template. + */ + +/* + * 'A' An upper case char + * 'a' A lower case char + * ' ' A space + * '0' A digit + * 'O' An optional digit or space + * ':' A colon + * 'N' A new line + */ +char ctype[] = "Aaa Aaa O0 00:00:00 0000"; +char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; + +int +isdate(date) + char date[]; +{ + + return cmatch(date, ctype) || cmatch(date, tmztype); +} + +/* + * Match the given string (cp) against the given template (tp). + * Return 1 if they match, 0 if they don't + */ +int +cmatch(cp, tp) + register char *cp, *tp; +{ + + while (*cp && *tp) + switch (*tp++) { + case 'a': + if (!islower(*cp++)) + return 0; + break; + case 'A': + if (!isupper(*cp++)) + return 0; + break; + case ' ': + if (*cp++ != ' ') + return 0; + break; + case '0': + if (!isdigit(*cp++)) + return 0; + break; + case 'O': + if (*cp != ' ' && !isdigit(*cp)) + return 0; + cp++; + break; + case ':': + if (*cp++ != ':') + return 0; + break; + case 'N': + if (*cp++ != '\n') + return 0; + break; + } + if (*cp || *tp) + return 0; + return (1); +} + +/* + * Collect a liberal (space, tab delimited) word into the word buffer + * passed. Also, return a pointer to the next word following that, + * or NOSTR if none follow. + */ +char * +nextword(wp, wbuf) + register char *wp, *wbuf; +{ + register c; + + if (wp == NOSTR) { + *wbuf = 0; + return (NOSTR); + } + while ((c = *wp++) && c != ' ' && c != '\t') { + *wbuf++ = c; + if (c == '"') { + while ((c = *wp++) && c != '"') + *wbuf++ = c; + if (c == '"') + *wbuf++ = c; + else + wp--; + } + } + *wbuf = '\0'; + for (; c == ' ' || c == '\t'; c = *wp++) + ; + if (c == 0) + return (NOSTR); + return (wp - 1); +} diff --git a/usr.bin/mail/lex.c b/usr.bin/mail/lex.c new file mode 100644 index 0000000..3428203 --- /dev/null +++ b/usr.bin/mail/lex.c @@ -0,0 +1,665 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * Lexical processing of commands. + */ + +char *prompt = "& "; + +/* + * Set up editing on the given file name. + * If the first character of name is %, we are considered to be + * editing the file, otherwise we are reading our mail which has + * signficance for mbox and so forth. + */ +int +setfile(name) + char *name; +{ + FILE *ibuf; + int i; + struct stat stb; + char isedit = *name != '%'; + char *who = name[1] ? name + 1 : myname; + static int shudclob; + extern char tempMesg[]; + extern int errno; + + if ((name = expand(name)) == NOSTR) + return -1; + + if ((ibuf = Fopen(name, "r")) == NULL) { + if (!isedit && errno == ENOENT) + goto nomail; + perror(name); + return(-1); + } + + if (fstat(fileno(ibuf), &stb) < 0) { + perror("fstat"); + Fclose(ibuf); + return (-1); + } + + switch (stb.st_mode & S_IFMT) { + case S_IFDIR: + Fclose(ibuf); + errno = EISDIR; + perror(name); + return (-1); + + case S_IFREG: + break; + + default: + Fclose(ibuf); + errno = EINVAL; + perror(name); + return (-1); + } + + /* + * Looks like all will be well. We must now relinquish our + * hold on the current set of stuff. Must hold signals + * while we are reading the new file, else we will ruin + * the message[] data structure. + */ + + holdsigs(); + if (shudclob) + quit(); + + /* + * Copy the messages into /tmp + * and set pointers. + */ + + readonly = 0; + if ((i = open(name, 1)) < 0) + readonly++; + else + close(i); + if (shudclob) { + fclose(itf); + fclose(otf); + } + shudclob = 1; + edit = isedit; + strcpy(prevfile, mailname); + if (name != mailname) + strcpy(mailname, name); + mailsize = fsize(ibuf); + if ((otf = fopen(tempMesg, "w")) == NULL) { + perror(tempMesg); + exit(1); + } + (void) fcntl(fileno(otf), F_SETFD, 1); + if ((itf = fopen(tempMesg, "r")) == NULL) { + perror(tempMesg); + exit(1); + } + (void) fcntl(fileno(itf), F_SETFD, 1); + rm(tempMesg); + setptr(ibuf); + setmsize(msgCount); + Fclose(ibuf); + relsesigs(); + sawcom = 0; + if (!edit && msgCount == 0) { +nomail: + fprintf(stderr, "No mail for %s\n", who); + return -1; + } + return(0); +} + +int *msgvec; +int reset_on_stop; /* do a reset() if stopped */ + +/* + * Interpret user commands one by one. If standard input is not a tty, + * print no prompt. + */ +void +commands() +{ + int eofloop = 0; + register int n; + char linebuf[LINESIZE]; + void intr(), stop(), hangup(); + + if (!sourcing) { + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, intr); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, hangup); + signal(SIGTSTP, stop); + signal(SIGTTOU, stop); + signal(SIGTTIN, stop); + } + setexit(); + for (;;) { + /* + * Print the prompt, if needed. Clear out + * string space, and flush the output. + */ + if (!sourcing && value("interactive") != NOSTR) { + reset_on_stop = 1; + printf(prompt); + } + fflush(stdout); + sreset(); + /* + * Read a line of commands from the current input + * and handle end of file specially. + */ + n = 0; + for (;;) { + if (readline(input, &linebuf[n], LINESIZE - n) < 0) { + if (n == 0) + n = -1; + break; + } + if ((n = strlen(linebuf)) == 0) + break; + n--; + if (linebuf[n] != '\\') + break; + linebuf[n++] = ' '; + } + reset_on_stop = 0; + if (n < 0) { + /* eof */ + if (loading) + break; + if (sourcing) { + unstack(); + continue; + } + if (value("interactive") != NOSTR && + value("ignoreeof") != NOSTR && + ++eofloop < 25) { + printf("Use \"quit\" to quit.\n"); + continue; + } + break; + } + eofloop = 0; + if (execute(linebuf, 0)) + break; + } +} + +/* + * Execute a single command. + * Command functions return 0 for success, 1 for error, and -1 + * for abort. A 1 or -1 aborts a load or source. A -1 aborts + * the interactive command loop. + * Contxt is non-zero if called while composing mail. + */ +int +execute(linebuf, contxt) + char linebuf[]; + int contxt; +{ + char word[LINESIZE]; + char *arglist[MAXARGC]; + struct cmd *com; + register char *cp, *cp2; + register int c; + int muvec[2]; + int e = 1; + + /* + * Strip the white space away from the beginning + * of the command, then scan out a word, which + * consists of anything except digits and white space. + * + * Handle ! escapes differently to get the correct + * lexical conventions. + */ + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (*cp == '!') { + if (sourcing) { + printf("Can't \"!\" while sourcing\n"); + goto out; + } + shell(cp+1); + return(0); + } + cp2 = word; + while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR) + *cp2++ = *cp++; + *cp2 = '\0'; + + /* + * Look up the command; if not found, bitch. + * Normally, a blank command would map to the + * first command in the table; while sourcing, + * however, we ignore blank lines to eliminate + * confusion. + */ + + if (sourcing && *word == '\0') + return(0); + com = lex(word); + if (com == NONE) { + printf("Unknown command: \"%s\"\n", word); + goto out; + } + + /* + * See if we should execute the command -- if a conditional + * we always execute it, otherwise, check the state of cond. + */ + + if ((com->c_argtype & F) == 0) + if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode) + return(0); + + /* + * Process the arguments to the command, depending + * on the type he expects. Default to an error. + * If we are sourcing an interactive command, it's + * an error. + */ + + if (!rcvmode && (com->c_argtype & M) == 0) { + printf("May not execute \"%s\" while sending\n", + com->c_name); + goto out; + } + if (sourcing && com->c_argtype & I) { + printf("May not execute \"%s\" while sourcing\n", + com->c_name); + goto out; + } + if (readonly && com->c_argtype & W) { + printf("May not execute \"%s\" -- message file is read only\n", + com->c_name); + goto out; + } + if (contxt && com->c_argtype & R) { + printf("Cannot recursively invoke \"%s\"\n", com->c_name); + goto out; + } + switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { + case MSGLIST: + /* + * A message list defaulting to nearest forward + * legal message. + */ + if (msgvec == 0) { + printf("Illegal use of \"message list\"\n"); + break; + } + if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) + break; + if (c == 0) { + *msgvec = first(com->c_msgflag, + com->c_msgmask); + msgvec[1] = NULL; + } + if (*msgvec == NULL) { + printf("No applicable messages\n"); + break; + } + e = (*com->c_func)(msgvec); + break; + + case NDMLIST: + /* + * A message list with no defaults, but no error + * if none exist. + */ + if (msgvec == 0) { + printf("Illegal use of \"message list\"\n"); + break; + } + if (getmsglist(cp, msgvec, com->c_msgflag) < 0) + break; + e = (*com->c_func)(msgvec); + break; + + case STRLIST: + /* + * Just the straight string, with + * leading blanks removed. + */ + while (isspace(*cp)) + cp++; + e = (*com->c_func)(cp); + break; + + case RAWLIST: + /* + * A vector of strings, in shell style. + */ + if ((c = getrawlist(cp, arglist, + sizeof arglist / sizeof *arglist)) < 0) + break; + if (c < com->c_minargs) { + printf("%s requires at least %d arg(s)\n", + com->c_name, com->c_minargs); + break; + } + if (c > com->c_maxargs) { + printf("%s takes no more than %d arg(s)\n", + com->c_name, com->c_maxargs); + break; + } + e = (*com->c_func)(arglist); + break; + + case NOLIST: + /* + * Just the constant zero, for exiting, + * eg. + */ + e = (*com->c_func)(0); + break; + + default: + panic("Unknown argtype"); + } + +out: + /* + * Exit the current source file on + * error. + */ + if (e) { + if (e < 0) + return 1; + if (loading) + return 1; + if (sourcing) + unstack(); + return 0; + } + if (value("autoprint") != NOSTR && com->c_argtype & P) + if ((dot->m_flag & MDELETED) == 0) { + muvec[0] = dot - &message[0] + 1; + muvec[1] = 0; + type(muvec); + } + if (!sourcing && (com->c_argtype & T) == 0) + sawcom = 1; + return(0); +} + +/* + * Set the size of the message vector used to construct argument + * lists to message list functions. + */ +void +setmsize(sz) + int sz; +{ + + if (msgvec != 0) + free((char *) msgvec); + msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec); +} + +/* + * Find the correct command in the command table corresponding + * to the passed command "word" + */ + +struct cmd * +lex(word) + char word[]; +{ + register struct cmd *cp; + extern struct cmd cmdtab[]; + + for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) + if (isprefix(word, cp->c_name)) + return(cp); + return(NONE); +} + +/* + * Determine if as1 is a valid prefix of as2. + * Return true if yep. + */ +int +isprefix(as1, as2) + char *as1, *as2; +{ + register char *s1, *s2; + + s1 = as1; + s2 = as2; + while (*s1++ == *s2) + if (*s2++ == '\0') + return(1); + return(*--s1 == '\0'); +} + +/* + * The following gets called on receipt of an interrupt. This is + * to abort printout of a command, mainly. + * Dispatching here when command() is inactive crashes rcv. + * Close all open files except 0, 1, 2, and the temporary. + * Also, unstack all source files. + */ + +int inithdr; /* am printing startup headers */ + +/*ARGSUSED*/ +void +intr(s) + int s; +{ + + noreset = 0; + if (!inithdr) + sawcom++; + inithdr = 0; + while (sourcing) + unstack(); + + close_all_files(); + + if (image >= 0) { + close(image); + image = -1; + } + fprintf(stderr, "Interrupt\n"); + reset(0); +} + +/* + * When we wake up after ^Z, reprint the prompt. + */ +void +stop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + if (reset_on_stop) { + reset_on_stop = 0; + reset(0); + } +} + +/* + * Branch here on hangup signal and simulate "exit". + */ +/*ARGSUSED*/ +void +hangup(s) + int s; +{ + + /* nothing to do? */ + exit(1); +} + +/* + * Announce the presence of the current Mail version, + * give the message count, and print a header listing. + */ +void +announce() +{ + int vec[2], mdot; + + mdot = newfileinfo(); + vec[0] = mdot; + vec[1] = 0; + dot = &message[mdot - 1]; + if (msgCount > 0 && value("noheader") == NOSTR) { + inithdr++; + headers(vec); + inithdr = 0; + } +} + +/* + * Announce information about the file we are editing. + * Return a likely place to set dot. + */ +int +newfileinfo() +{ + register struct message *mp; + register int u, n, mdot, d, s; + char fname[BUFSIZ], zname[BUFSIZ], *ename; + + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MNEW) + break; + if (mp >= &message[msgCount]) + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag & MREAD) == 0) + break; + if (mp < &message[msgCount]) + mdot = mp - &message[0] + 1; + else + mdot = 1; + s = d = 0; + for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) + n++; + if ((mp->m_flag & MREAD) == 0) + u++; + if (mp->m_flag & MDELETED) + d++; + if (mp->m_flag & MSAVED) + s++; + } + ename = mailname; + if (getfold(fname) >= 0) { + strcat(fname, "/"); + if (strncmp(fname, mailname, strlen(fname)) == 0) { + sprintf(zname, "+%s", mailname + strlen(fname)); + ename = zname; + } + } + printf("\"%s\": ", ename); + if (msgCount == 1) + printf("1 message"); + else + printf("%d messages", msgCount); + if (n > 0) + printf(" %d new", n); + if (u-n > 0) + printf(" %d unread", u); + if (d > 0) + printf(" %d deleted", d); + if (s > 0) + printf(" %d saved", s); + if (readonly) + printf(" [Read only]"); + printf("\n"); + return(mdot); +} + +/* + * Print the current version number. + */ + +/*ARGSUSED*/ +int +pversion(e) + int e; +{ + extern char *version; + + printf("Version %s\n", version); + return(0); +} + +/* + * Load a file of user definitions. + */ +void +load(name) + char *name; +{ + register FILE *in, *oldin; + + if ((in = Fopen(name, "r")) == NULL) + return; + oldin = input; + input = in; + loading = 1; + sourcing = 1; + commands(); + loading = 0; + sourcing = 0; + input = oldin; + Fclose(in); +} diff --git a/usr.bin/mail/list.c b/usr.bin/mail/list.c new file mode 100644 index 0000000..18cf1eb --- /dev/null +++ b/usr.bin/mail/list.c @@ -0,0 +1,801 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)list.c 8.2 (Berkeley) 4/19/94"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * Message list handling. + */ + +/* + * Convert the user string of message numbers and + * store the numbers into vector. + * + * Returns the count of messages picked up or -1 on error. + */ +int +getmsglist(buf, vector, flags) + char *buf; + int *vector, flags; +{ + register int *ip; + register struct message *mp; + + if (msgCount == 0) { + *vector = 0; + return 0; + } + if (markall(buf, flags) < 0) + return(-1); + ip = vector; + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MMARK) + *ip++ = mp - &message[0] + 1; + *ip = 0; + return(ip - vector); +} + +/* + * Mark all messages that the user wanted from the command + * line in the message structure. Return 0 on success, -1 + * on error. + */ + +/* + * Bit values for colon modifiers. + */ + +#define CMNEW 01 /* New messages */ +#define CMOLD 02 /* Old messages */ +#define CMUNREAD 04 /* Unread messages */ +#define CMDELETED 010 /* Deleted messages */ +#define CMREAD 020 /* Read messages */ + +/* + * The following table describes the letters which can follow + * the colon and gives the corresponding modifier bit. + */ + +struct coltab { + char co_char; /* What to find past : */ + int co_bit; /* Associated modifier bit */ + int co_mask; /* m_status bits to mask */ + int co_equal; /* ... must equal this */ +} coltab[] = { + 'n', CMNEW, MNEW, MNEW, + 'o', CMOLD, MNEW, 0, + 'u', CMUNREAD, MREAD, 0, + 'd', CMDELETED, MDELETED, MDELETED, + 'r', CMREAD, MREAD, MREAD, + 0, 0, 0, 0 +}; + +static int lastcolmod; + +int +markall(buf, f) + char buf[]; + int f; +{ + register char **np; + register int i; + register struct message *mp; + char *namelist[NMLSIZE], *bufp; + int tok, beg, mc, star, other, valdot, colmod, colresult; + + valdot = dot - &message[0] + 1; + colmod = 0; + for (i = 1; i <= msgCount; i++) + unmark(i); + bufp = buf; + mc = 0; + np = &namelist[0]; + scaninit(); + tok = scan(&bufp); + star = 0; + other = 0; + beg = 0; + while (tok != TEOL) { + switch (tok) { + case TNUMBER: +number: + if (star) { + printf("No numbers mixed with *\n"); + return(-1); + } + mc++; + other++; + if (beg != 0) { + if (check(lexnumber, f)) + return(-1); + for (i = beg; i <= lexnumber; i++) + if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) + mark(i); + beg = 0; + break; + } + beg = lexnumber; + if (check(beg, f)) + return(-1); + tok = scan(&bufp); + regret(tok); + if (tok != TDASH) { + mark(beg); + beg = 0; + } + break; + + case TPLUS: + if (beg != 0) { + printf("Non-numeric second argument\n"); + return(-1); + } + i = valdot; + do { + i++; + if (i > msgCount) { + printf("Referencing beyond EOF\n"); + return(-1); + } + } while ((message[i - 1].m_flag & MDELETED) != f); + mark(i); + break; + + case TDASH: + if (beg == 0) { + i = valdot; + do { + i--; + if (i <= 0) { + printf("Referencing before 1\n"); + return(-1); + } + } while ((message[i - 1].m_flag & MDELETED) != f); + mark(i); + } + break; + + case TSTRING: + if (beg != 0) { + printf("Non-numeric second argument\n"); + return(-1); + } + other++; + if (lexstring[0] == ':') { + colresult = evalcol(lexstring[1]); + if (colresult == 0) { + printf("Unknown colon modifier \"%s\"\n", + lexstring); + return(-1); + } + colmod |= colresult; + } + else + *np++ = savestr(lexstring); + break; + + case TDOLLAR: + case TUP: + case TDOT: + lexnumber = metamess(lexstring[0], f); + if (lexnumber == -1) + return(-1); + goto number; + + case TSTAR: + if (other) { + printf("Can't mix \"*\" with anything\n"); + return(-1); + } + star++; + break; + + case TERROR: + return -1; + } + tok = scan(&bufp); + } + lastcolmod = colmod; + *np = NOSTR; + mc = 0; + if (star) { + for (i = 0; i < msgCount; i++) + if ((message[i].m_flag & MDELETED) == f) { + mark(i+1); + mc++; + } + if (mc == 0) { + printf("No applicable messages.\n"); + return(-1); + } + return(0); + } + + /* + * If no numbers were given, mark all of the messages, + * so that we can unmark any whose sender was not selected + * if any user names were given. + */ + + if ((np > namelist || colmod != 0) && mc == 0) + for (i = 1; i <= msgCount; i++) + if ((message[i-1].m_flag & MDELETED) == f) + mark(i); + + /* + * If any names were given, go through and eliminate any + * messages whose senders were not requested. + */ + + if (np > namelist) { + for (i = 1; i <= msgCount; i++) { + for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) + if (**np == '/') { + if (matchsubj(*np, i)) { + mc++; + break; + } + } + else { + if (matchsender(*np, i)) { + mc++; + break; + } + } + if (mc == 0) + unmark(i); + } + + /* + * Make sure we got some decent messages. + */ + + mc = 0; + for (i = 1; i <= msgCount; i++) + if (message[i-1].m_flag & MMARK) { + mc++; + break; + } + if (mc == 0) { + printf("No applicable messages from {%s", + namelist[0]); + for (np = &namelist[1]; *np != NOSTR; np++) + printf(", %s", *np); + printf("}\n"); + return(-1); + } + } + + /* + * If any colon modifiers were given, go through and + * unmark any messages which do not satisfy the modifiers. + */ + + if (colmod != 0) { + for (i = 1; i <= msgCount; i++) { + register struct coltab *colp; + + mp = &message[i - 1]; + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_bit & colmod) + if ((mp->m_flag & colp->co_mask) + != colp->co_equal) + unmark(i); + + } + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MMARK) + break; + if (mp >= &message[msgCount]) { + register struct coltab *colp; + + printf("No messages satisfy"); + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_bit & colmod) + printf(" :%c", colp->co_char); + printf("\n"); + return(-1); + } + } + return(0); +} + +/* + * Turn the character after a colon modifier into a bit + * value. + */ +int +evalcol(col) + int col; +{ + register struct coltab *colp; + + if (col == 0) + return(lastcolmod); + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_char == col) + return(colp->co_bit); + return(0); +} + +/* + * Check the passed message number for legality and proper flags. + * If f is MDELETED, then either kind will do. Otherwise, the message + * has to be undeleted. + */ +int +check(mesg, f) + int mesg, f; +{ + register struct message *mp; + + if (mesg < 1 || mesg > msgCount) { + printf("%d: Invalid message number\n", mesg); + return(-1); + } + mp = &message[mesg-1]; + if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { + printf("%d: Inappropriate message\n", mesg); + return(-1); + } + return(0); +} + +/* + * Scan out the list of string arguments, shell style + * for a RAWLIST. + */ +int +getrawlist(line, argv, argc) + char line[]; + char **argv; + int argc; +{ + register char c, *cp, *cp2, quotec; + int argn; + char linebuf[BUFSIZ]; + + argn = 0; + cp = line; + for (;;) { + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + if (*cp == '\0') + break; + if (argn >= argc - 1) { + printf( + "Too many elements in the list; excess discarded.\n"); + break; + } + cp2 = linebuf; + quotec = '\0'; + while ((c = *cp) != '\0') { + cp++; + if (quotec != '\0') { + if (c == quotec) + quotec = '\0'; + else if (c == '\\') + switch (c = *cp++) { + case '\0': + *cp2++ = '\\'; + cp--; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + if (*cp >= '0' && *cp <= '7') + c = c * 8 + *cp++ - '0'; + if (*cp >= '0' && *cp <= '7') + c = c * 8 + *cp++ - '0'; + *cp2++ = c; + break; + case 'b': + *cp2++ = '\b'; + break; + case 'f': + *cp2++ = '\f'; + break; + case 'n': + *cp2++ = '\n'; + break; + case 'r': + *cp2++ = '\r'; + break; + case 't': + *cp2++ = '\t'; + break; + case 'v': + *cp2++ = '\v'; + break; + default: + *cp2++ = c; + } + else if (c == '^') { + c = *cp++; + if (c == '?') + *cp2++ = '\177'; + /* null doesn't show up anyway */ + else if (c >= 'A' && c <= '_' || + c >= 'a' && c <= 'z') + *cp2++ = c & 037; + else { + *cp2++ = '^'; + cp--; + } + } else + *cp2++ = c; + } else if (c == '"' || c == '\'') + quotec = c; + else if (c == ' ' || c == '\t') + break; + else + *cp2++ = c; + } + *cp2 = '\0'; + argv[argn++] = savestr(linebuf); + } + argv[argn] = NOSTR; + return argn; +} + +/* + * scan out a single lexical item and return its token number, + * updating the string pointer passed **p. Also, store the value + * of the number or string scanned in lexnumber or lexstring as + * appropriate. In any event, store the scanned `thing' in lexstring. + */ + +struct lex { + char l_char; + char l_token; +} singles[] = { + '$', TDOLLAR, + '.', TDOT, + '^', TUP, + '*', TSTAR, + '-', TDASH, + '+', TPLUS, + '(', TOPEN, + ')', TCLOSE, + 0, 0 +}; + +int +scan(sp) + char **sp; +{ + register char *cp, *cp2; + register int c; + register struct lex *lp; + int quotec; + + if (regretp >= 0) { + strcpy(lexstring, string_stack[regretp]); + lexnumber = numberstack[regretp]; + return(regretstack[regretp--]); + } + cp = *sp; + cp2 = lexstring; + c = *cp++; + + /* + * strip away leading white space. + */ + + while (c == ' ' || c == '\t') + c = *cp++; + + /* + * If no characters remain, we are at end of line, + * so report that. + */ + + if (c == '\0') { + *sp = --cp; + return(TEOL); + } + + /* + * If the leading character is a digit, scan + * the number and convert it on the fly. + * Return TNUMBER when done. + */ + + if (isdigit(c)) { + lexnumber = 0; + while (isdigit(c)) { + lexnumber = lexnumber*10 + c - '0'; + *cp2++ = c; + c = *cp++; + } + *cp2 = '\0'; + *sp = --cp; + return(TNUMBER); + } + + /* + * Check for single character tokens; return such + * if found. + */ + + for (lp = &singles[0]; lp->l_char != 0; lp++) + if (c == lp->l_char) { + lexstring[0] = c; + lexstring[1] = '\0'; + *sp = cp; + return(lp->l_token); + } + + /* + * We've got a string! Copy all the characters + * of the string into lexstring, until we see + * a null, space, or tab. + * If the lead character is a " or ', save it + * and scan until you get another. + */ + + quotec = 0; + if (c == '\'' || c == '"') { + quotec = c; + c = *cp++; + } + while (c != '\0') { + if (c == quotec) { + cp++; + break; + } + if (quotec == 0 && (c == ' ' || c == '\t')) + break; + if (cp2 - lexstring < STRINGLEN-1) + *cp2++ = c; + c = *cp++; + } + if (quotec && c == 0) { + fprintf(stderr, "Missing %c\n", quotec); + return TERROR; + } + *sp = --cp; + *cp2 = '\0'; + return(TSTRING); +} + +/* + * Unscan the named token by pushing it onto the regret stack. + */ +void +regret(token) + int token; +{ + if (++regretp >= REGDEP) + panic("Too many regrets"); + regretstack[regretp] = token; + lexstring[STRINGLEN-1] = '\0'; + string_stack[regretp] = savestr(lexstring); + numberstack[regretp] = lexnumber; +} + +/* + * Reset all the scanner global variables. + */ +void +scaninit() +{ + regretp = -1; +} + +/* + * Find the first message whose flags & m == f and return + * its message number. + */ +int +first(f, m) + int f, m; +{ + register struct message *mp; + + if (msgCount == 0) + return 0; + f &= MDELETED; + m &= MDELETED; + for (mp = dot; mp < &message[msgCount]; mp++) + if ((mp->m_flag & m) == f) + return mp - message + 1; + for (mp = dot-1; mp >= &message[0]; mp--) + if ((mp->m_flag & m) == f) + return mp - message + 1; + return 0; +} + +/* + * See if the passed name sent the passed message number. Return true + * if so. + */ +int +matchsender(str, mesg) + char *str; + int mesg; +{ + register char *cp, *cp2, *backup; + + if (!*str) /* null string matches nothing instead of everything */ + return 0; + backup = cp2 = nameof(&message[mesg - 1], 0); + cp = str; + while (*cp2) { + if (*cp == 0) + return(1); + if (raise(*cp++) != raise(*cp2++)) { + cp2 = ++backup; + cp = str; + } + } + return(*cp == 0); +} + +/* + * See if the given string matches inside the subject field of the + * given message. For the purpose of the scan, we ignore case differences. + * If it does, return true. The string search argument is assumed to + * have the form "/search-string." If it is of the form "/," we use the + * previous search string. + */ + +char lastscan[128]; +int +matchsubj(str, mesg) + char *str; + int mesg; +{ + register struct message *mp; + register char *cp, *cp2, *backup; + + str++; + if (strlen(str) == 0) + str = lastscan; + else + strcpy(lastscan, str); + mp = &message[mesg-1]; + + /* + * Now look, ignoring case, for the word in the string. + */ + + if (value("searchheaders") && (cp = index(str, ':'))) { + *cp++ = '\0'; + cp2 = hfield(str, mp); + cp[-1] = ':'; + str = cp; + } else { + cp = str; + cp2 = hfield("subject", mp); + } + if (cp2 == NOSTR) + return(0); + backup = cp2; + while (*cp2) { + if (*cp == 0) + return(1); + if (raise(*cp++) != raise(*cp2++)) { + cp2 = ++backup; + cp = str; + } + } + return(*cp == 0); +} + +/* + * Mark the named message by setting its mark bit. + */ +void +mark(mesg) + int mesg; +{ + register int i; + + i = mesg; + if (i < 1 || i > msgCount) + panic("Bad message number to mark"); + message[i-1].m_flag |= MMARK; +} + +/* + * Unmark the named message. + */ +void +unmark(mesg) + int mesg; +{ + register int i; + + i = mesg; + if (i < 1 || i > msgCount) + panic("Bad message number to unmark"); + message[i-1].m_flag &= ~MMARK; +} + +/* + * Return the message number corresponding to the passed meta character. + */ +int +metamess(meta, f) + int meta, f; +{ + register int c, m; + register struct message *mp; + + c = meta; + switch (c) { + case '^': + /* + * First 'good' message left. + */ + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag & MDELETED) == f) + return(mp - &message[0] + 1); + printf("No applicable messages\n"); + return(-1); + + case '$': + /* + * Last 'good message left. + */ + for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) + if ((mp->m_flag & MDELETED) == f) + return(mp - &message[0] + 1); + printf("No applicable messages\n"); + return(-1); + + case '.': + /* + * Current message. + */ + m = dot - &message[0] + 1; + if ((dot->m_flag & MDELETED) != f) { + printf("%d: Inappropriate message\n", m); + return(-1); + } + return(m); + + default: + printf("Unknown metachar (%c)\n", c); + return(-1); + } +} diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1 new file mode 100644 index 0000000..ecf5868 --- /dev/null +++ b/usr.bin/mail/mail.1 @@ -0,0 +1,1030 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt MAIL 1 +.Os BSD 4 +.Sh NAME +.Nm mail +.Nd send and receive mail +.Sh SYNOPSIS +.Nm mail +.Op Fl iInv +.Op Fl s Ar subject +.Op Fl c Ar cc-addr +.Op Fl b Ar bcc-addr +.Ar to-addr... +.Nm mail +.Op Fl iInNv +.Fl f +.Op Ar name +.Nm mail +.Op Fl iInNv +.Op Fl u Ar user +.Sh INTRODUCTION +.Nm Mail +is an intelligent mail processing system, which has +a command syntax reminiscent of +.Xr \&ed 1 +with lines replaced by messages. +.Pp +.Bl -tag -width flag +.It Fl v +Verbose mode. +The details of +delivery are displayed on the user's terminal. +.It Fl i +Ignore tty interrupt signals. +This is +particularly useful when using +.Nm mail +on noisy phone lines. +.It Fl I +Forces mail to run in interactive mode even when +input isn't a terminal. +In particular, the +.Sq Ic \&~ +special +character when sending mail is only active in interactive mode. +.It Fl n +Inhibits reading +.Pa /usr/share/misc/Mail.rc +upon startup. +.It Fl N +Inhibits the initial display of message headers +when reading mail or editing a mail folder. +.It Fl s +Specify subject on command line +(only the first argument after the +.Fl s +flag is used as a subject; be careful to quote subjects +containing spaces.) +.It Fl c +Send carbon copies to +.Ar list +of users. +.It Fl b +Send blind carbon copies to +.Ar list . +List should be a comma-separated list of names. +.It Fl f +Read in the contents of your +.Ar mbox +(or the specified file) +for processing; when you +.Ar quit , +.Nm mail +writes undeleted messages back to this file. +.It Fl u +Is equivalent to: +.Pp +.Dl mail -f /var/spool/mail/user +.El +.Ss Sending mail +To send a message to one or more people, +.Nm mail +can be invoked with arguments which are the names of people to +whom the mail will be sent. +You are then expected to type in +your message, followed +by an +.Sq Li control\-D +at the beginning of a line. +The section below +.Ar Replying to or originating mail , +describes some features of +.Nm mail +available to help you compose your letter. +.Pp +.Ss Reading mail +In normal usage +.Nm mail +is given no arguments and checks your mail out of the +post office, then +prints out a one line header of each message found. +The current message is initially the first message (numbered 1) +and can be printed using the +.Ic print +command (which can be abbreviated +.Ql Ic p ) . +You can move among the messages much as you move between lines in +.Xr \&ed 1 , +with the commands +.Ql Ic \&+ +and +.Ql Ic \&\- +moving backwards and forwards, and +simple numbers. +.Pp +.Ss Disposing of mail. +After examining a message you can +.Ic delete +.Ql Ic d ) +the message or +.Ic reply +.Ql Ic r ) +to it. +Deletion causes the +.Nm mail +program to forget about the message. +This is not irreversible; the message can be +.Ic undeleted +.Ql Ic u ) +by giving its number, or the +.Nm mail +session can be aborted by giving the +.Ic exit +.Ql Ic x ) +command. +Deleted messages will, however, usually disappear never to be seen again. +.Pp +.Ss Specifying messages +Commands such as +.Ic print +and +.Ic delete +can be given a list of message numbers as arguments to apply +to a number of messages at once. +Thus +.Dq Li delete 1 2 +deletes messages 1 and 2, while +.Dq Li delete 1\-5 +deletes messages 1 through 5. +The special name +.Ql Li \&* +addresses all messages, and +.Ql Li \&$ +addresses +the last message; thus the command +.Ic top +which prints the first few lines of a message could be used in +.Dq Li top \&* +to print the first few lines of all messages. +.Pp +.Ss Replying to or originating mail. +You can use the +.Ic reply +command to +set up a response to a message, sending it back to the +person who it was from. +Text you then type in, up to an end-of-file, +defines the contents of the message. +While you are composing a message, +.Nm mail +treats lines beginning with the character +.Ql Ic \&~ +specially. +For instance, typing +.Ql Ic \&~m +(alone on a line) will place a copy +of the current message into the response right shifting it by a tabstop +(see +.Em indentprefix +variable, below). +Other escapes will set up subject fields, add and delete recipients +to the message and allow you to escape to an editor to revise the +message or to a shell to run some commands. +(These options +are given in the summary below.) +.Pp +.Ss Ending a mail processing session. +You can end a +.Nm mail +session with the +.Ic quit +.Ql Ic q ) +command. +Messages which have been examined go to your +.Ar mbox +file unless they have been deleted in which case they are discarded. +Unexamined messages go back to the post office. +(See the +.Fl f +option above). +.Pp +.Ss Personal and systemwide distribution lists. +It is also possible to create a personal distribution lists so that, +for instance, you can send mail to +.Dq Li cohorts +and have it go +to a group of people. +Such lists can be defined by placing a line like +.Pp +.Dl alias cohorts bill ozalp jkf mark kridle@ucbcory +.Pp +in the file +.Pa \&.mailrc +in your home directory. +The current list of such aliases can be displayed with the +.Ic alias +command in +.Nm mail . +System wide distribution lists can be created by editing +.Pa /etc/aliases , +see +.Xr aliases 5 +and +.Xr sendmail 8 ; +these are kept in a different syntax. +In mail you send, personal aliases will be expanded in mail sent +to others so that they will be able to +.Ic reply +to the recipients. +System wide +.Ic aliases +are not expanded when the mail is sent, +but any reply returned to the machine will have the system wide +alias expanded as all mail goes through +.Xr sendmail . +.Pp +.Ss Network mail (ARPA, UUCP, Berknet) +See +.Xr mailaddr 7 +for a description of network addresses. +.Pp +.Nm Mail +has a number of options which can be set in the +.Pa .mailrc +file to alter its behavior; thus +.Dq Li set askcc +enables the +.Ar askcc +feature. +(These options are summarized below.) +.Sh SUMMARY +(Adapted from the `Mail Reference Manual') +.Pp +Each command is typed on a line by itself, and may take arguments +following the command word. +The command need not be typed in its +entirety \- the first command which matches the typed prefix is used. +For commands which take message lists as arguments, if no message +list is given, then the next message forward which satisfies the +command's requirements is used. +If there are no messages forward of +the current message, the search proceeds backwards, and if there are no +good messages at all, +.Nm mail +types +.Dq Li No applicable messages +and +aborts the command. +.Bl -tag -width delete +.It Ic \&\- +Print out the preceding message. +If given a numeric +argument +.Ar n , +goes to the +.Ar n Ns 'th +previous message and prints it. +.It Ic \&? +Prints a brief summary of commands. +.It Ic \&! +Executes the shell +(see +.Xr sh 1 +and +.Xr csh 1 ) +command which follows. +.It Ic Print +.Pq Ic P +Like +.Ic print +but also prints out ignored header fields. +See also +.Ic print , +.Ic ignore +and +.Ic retain . +.It Ic Reply +.Pq Ic R +Reply to originator. +Does not reply to other +recipients of the original message. +.It Ic Type +.Pq Ic T +Identical to the +.Ic Print +command. +.It Ic alias +.Pq Ic a +With no arguments, prints out all currently-defined aliases. +With one +argument, prints out that alias. +With more than one argument, creates +a new alias or changes an old one. +.It Ic alternates +.Pq Ic alt +The +.Ic alternates +command is useful if you have accounts on several machines. +It can be used to inform +.Nm mail +that the listed addresses are really you. +When you +.Ic reply +to messages, +.Nm mail +will not send a copy of the message to any of the addresses +listed on the +.Ic alternates +list. +If the +.Ic alternates +command is given with no argument, the current set of alternate +names is displayed. +.It Ic chdir +.Pq Ic c +Changes the user's working directory to that specified, if given. +If +no directory is given, then changes to the user's login directory. +.It Ic copy +.Pq Ic co +The +.Ic copy +command does the same thing that +.Ic save +does, except that it does not mark the messages it +is used on for deletion when you quit. +.It Ic delete +.Pq Ic d +Takes a list of messages as argument and marks them all as deleted. +Deleted messages will not be saved in +.Ar mbox , +nor will they be available for most other commands. +.It Ic dp +(also +.Ic dt ) +Deletes the current message and prints the next message. +If there is no next message, +.Nm mail +says +.Dq Li "at EOF" . +.It Ic edit +.Pq Ic e +Takes a list of messages and points the text editor at each one in +turn. +On return from the editor, the message is read back in. +.It Ic exit +.Pf ( Ic ex +or +.Ic x ) +Effects an immediate return to the Shell without +modifying the user's system mailbox, his +.Ar mbox +file, or his edit file in +.Fl f . +.It Ic file +.Pq Ic fi +The same as +.Ic folder . +.It Ic folders +List the names of the folders in your folder directory. +.It Ic folder +.Pq Ic fo +The +.Ic folder +command switches to a new mail file or folder. +With no +arguments, it tells you which file you are currently reading. +If you give it an argument, it will write out changes (such +as deletions) you have made in the current file and read in +the new file. +Some special conventions are recognized for +the name. +# means the previous file, % means your system +mailbox, %user means user's system mailbox, & means +your +.Ar mbox +file, and +\&+\&folder means a file in your folder +directory. +.It Ic from +.Pq Ic f +Takes a list of messages and prints their message headers. +.It Ic headers +.Pq Ic h +Lists the current range of headers, which is an 18\-message group. +If +a +.Ql \&+ +argument is given, then the next 18\-message group is printed, and if +a +.Ql \&\- +argument is given, the previous 18\-message group is printed. +.It Ic help +A synonym for +.Ic \&? +.It Ic hold +.Pf ( Ic ho , +also +.Ic preserve ) +Takes a message list and marks each +message therein to be saved in the +user's system mailbox instead of in +.Ar mbox . +Does not override the +.Ic delete +command. +.It Ic ignore +Add the list of header fields named to the +.Ar ignored list . +Header fields in the ignore list are not printed +on your terminal when you print a message. +This +command is very handy for suppression of certain machine-generated +header fields. +The +.Ic Type +and +.Ic Print +commands can be used to print a message in its entirety, including +ignored fields. +If +.Ic ignore +is executed with no arguments, it lists the current set of +ignored fields. +.It Ic mail +.Pq Ic m +Takes as argument login names and distribution group names and sends +mail to those people. +.It Ic mbox +Indicate that a list of messages be sent to +.Ic mbox +in your home directory when you quit. +This is the default +action for messages if you do +.Em not +have the +.Ic hold +option set. +.It Ic next +.Pq Ic n +like +.Ic \&+ +or +.Tn CR ) +Goes to the next message in sequence and types it. +With an argument list, types the next matching message. +.It Ic preserve +.Pq Ic pre +A synonym for +.Ic hold . +.It Ic print +.Pq Ic p +Takes a message list and types out each message on the user's terminal. +.It Ic quit +.Pq Ic q +Terminates the session, saving all undeleted, unsaved messages in +the user's +.Ar mbox +file in his login directory, preserving all messages marked with +.Ic hold +or +.Ic preserve +or never referenced +in his system mailbox, and removing all other messages from his system +mailbox. +If new mail has arrived during the session, the message +.Dq Li "You have new mail" +is given. +If given while editing a +mailbox file with the +.Fl f +flag, then the edit file is rewritten. +A return to the Shell is +effected, unless the rewrite of edit file fails, in which case the user +can escape with the +.Ic exit +command. +.It Ic reply +.Pq Ic r +Takes a message list and sends mail to the sender and all +recipients of the specified message. +The default message must not be deleted. +.It Ic respond +A synonym for +.Ic reply . +.It Ic retain +Add the list of header fields named to the +.Ar retained list +Only the header fields in the retain list +are shown on your terminal when you print a message. +All other header fields are suppressed. +The +.Ic Type +and +.Ic Print +commands can be used to print a message in its entirety. +If +.Ic retain +is executed with no arguments, it lists the current set of +retained fields. +.It Ic save +.Pq Ic s +Takes a message list and a filename and appends each message in +turn to the end of the file. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +.It Ic set +.Pq Ic se +With no arguments, prints all variable values. +Otherwise, sets +option. +Arguments are of the form +.Ar option=value +(no space before or after =) or +.Ar option . +Quotation marks may be placed around any part of the assignment statement to +quote blanks or tabs, i.e. +.Dq Li "set indentprefix=\*q->\*q" +.It Ic saveignore +.Ic Saveignore +is to +.Ic save +what +.Ic ignore +is to +.Ic print +and +.Ic type . +Header fields thus marked are filtered out when +saving a message by +.Ic save +or when automatically saving to +.Ar mbox . +.It Ic saveretain +.Ic Saveretain +is to +.Ic save +what +.Ic retain +is to +.Ic print +and +.Ic type . +Header fields thus marked are the only ones saved +with a message when saving by +.Ic save +or when automatically saving to +.Ar mbox . +.Ic Saveretain +overrides +.Ic saveignore . +.It Ic shell +.Pq Ic sh +Invokes an interactive version of the shell. +.It Ic size +Takes a message list and prints out the size in characters of each +message. +.It Ic source +The +.Ic source +command reads +commands from a file. +.It Ic top +Takes a message list and prints the top few lines of each. +The number of +lines printed is controlled by the variable +.Ic toplines +and defaults to five. +.It Ic type +.Pq Ic t +A synonym for +.Ic print . +.It Ic unalias +Takes a list of names defined by +.Ic alias +commands and discards the remembered groups of users. +The group names +no longer have any significance. +.It Ic undelete +.Pq Ic u +Takes a message list and marks each message as +.Ic not +being deleted. +.It Ic unread +.Pq Ic U +Takes a message list and marks each message as +.Ic not +having been read. +.It Ic unset +Takes a list of option names and discards their remembered values; +the inverse of +.Ic set . +.It Ic visual +.Pq Ic v +Takes a message list and invokes the display editor on each message. +.It Ic write +.Pq Ic w +Similar to +.Ic save , +except that +.Ic only +the message body +.Pq Ar without +the header) is saved. +Extremely useful for such tasks as sending and receiving source +program text over the message system. +.It Ic xit +.Pq Ic x +A synonym for +.Ic exit . +.It Ic z +.Nm Mail +presents message headers in windowfuls as described under the +.Ic headers +command. +You can move +.Nm mail Ns 's +attention forward to the next window with the +.Ic \&z +command. +Also, you can move to the previous window by using +.Ic \&z\&\- . +.El +.Ss Tilde/Escapes +.Pp +Here is a summary of the tilde escapes, +which are used when composing messages to perform +special functions. +Tilde escapes are only recognized at the beginning +of lines. +The name +.Dq Em tilde\ escape +is somewhat of a misnomer since the actual escape character can be set +by the option +.Ic escape . +.Bl -tag -width Ds +.It Ic \&~! Ns Ar command +Execute the indicated shell command, then return to the message. +.It Ic \&~b Ns Ar name ... +Add the given names to the list of carbon copy recipients but do not make +the names visible in the Cc: line ("blind" carbon copy). +.It Ic \&~c Ns Ar name ... +Add the given names to the list of carbon copy recipients. +.It Ic \&~d +Read the file +.Dq Pa dead.letter +from your home directory into the message. +.It Ic \&~e +Invoke the text editor on the message collected so far. +After the +editing session is finished, you may continue appending text to the +message. +.It Ic \&~f Ns Ar messages +Read the named messages into the message being sent. +If no messages are specified, read in the current message. +Message headers currently being ignored (by the +.Ic ignore +or +.Ic retain +command) are not included. +.It Ic \&~F Ns Ar messages +Identical to +.Ic \&~f , +except all message headers are included. +.It Ic \&~h +Edit the message header fields by typing each one in turn and allowing +the user to append text to the end or modify the field by using the +current terminal erase and kill characters. +.It Ic \&~m Ns Ar messages +Read the named messages into the message being sent, indented by a +tab or by the value of +.Ar indentprefix . +If no messages are specified, +read the current message. +Message headers currently being ignored (by the +.Ic ignore +or +.Ic retain +command) are not included. +.It Ic \&~M Ns Ar messages +Identical to +.Ic \&~m , +except all message headers are included. +.It Ic \&~p +Print out the message collected so far, prefaced by the message header +fields. +.It Ic \&~q +Abort the message being sent, copying the message to +.Dq Pa dead.letter +in your home directory if +.Ic save +is set. +.It Ic \&~r Ns Ar filename +Read the named file into the message. +.It Ic \&~s Ns Ar string +Cause the named string to become the current subject field. +.It Ic \&~\&t Ns Ar name ... +Add the given names to the direct recipient list. +.It Ic \&~\&v +Invoke an alternate editor (defined by the +.Ev VISUAL +option) on the +message collected so far. +Usually, the alternate editor will be a +screen editor. +After you quit the editor, you may resume appending +text to the end of your message. +.It Ic \&~w Ns Ar filename +Write the message onto the named file. +.It Ic \&~\&| Ns Ar command +Pipe the message through the command as a filter. +If the command gives +no output or terminates abnormally, retain the original text of the +message. +The command +.Xr fmt 1 +is often used as +.Ic command +to rejustify the message. +.It Ic \&~: Ns Ar mail-command +Execute the given mail command. +Not all commands, however, are allowed. +.It Ic \&~~ Ns Ar string +Insert the string of text in the message prefaced by a single ~. +If +you have changed the escape character, then you should double +that character in order to send it. +.El +.Ss Mail Options +Options are controlled via +.Ic set +and +.Ic unset +commands. +Options may be either binary, in which case it is only +significant to see whether they are set or not; or string, in which +case the actual value is of interest. +The binary options include the following: +.Bl -tag -width append +.It Ar append +Causes messages saved in +.Ar mbox +to be appended to the end rather than prepended. +This should always be set (perhaps in +.Pa /usr/share/misc/Mail.rc ) . +.It Ar ask +Causes +.Nm mail +to prompt you for the subject of each message you send. +If +you respond with simply a newline, no subject field will be sent. +.It Ar askcc +Causes you to be prompted for additional carbon copy recipients at the +end of each message. +Responding with a newline indicates your +satisfaction with the current list. +.It Ar autoprint +Causes the +.Ic delete +command to behave like +.Ic dp +\- thus, after deleting a message, the next one will be typed +automatically. +.It Ar debug +Setting the binary option +.Ar debug +is the same as specifying +.Fl d +on the command line and causes +.Nm mail +to output all sorts of information useful for debugging +.Nm mail . +.It Ar dot +The binary option +.Ar dot +causes +.Nm mail +to interpret a period alone on a line as the terminator +of a message you are sending. +.It Ar hold +This option is used to hold messages in the system mailbox +by default. +.It Ar ignore +Causes interrupt signals from your terminal to be ignored and echoed as +@'s. +.It Ar ignoreeof +An option related to +.Ar dot +is +.Ar ignoreeof +which makes +.Nm mail +refuse to accept a control-d as the end of a message. +.Ar Ignoreeof +also applies to +.Nm mail +command mode. +.It Ar metoo +Usually, when a group is expanded that contains the sender, the sender +is removed from the expansion. +Setting this option causes the sender +to be included in the group. +.It Ar noheader +Setting the option +.Ar noheader +is the same as giving the +.Fl N +flag on the command line. +.It Ar nosave +Normally, when you abort a message with two +.Tn RUBOUT +(erase or delete) +.Nm mail +copies the partial letter to the file +.Dq Pa dead.letter +in your home directory. +Setting the binary option +.Ar nosave +prevents this. +.It Ar Replyall +Reverses the sense of +.Ic reply +and +.Ic Reply +commands. +.It Ar quiet +Suppresses the printing of the version when first invoked. +.It Ar searchheaders +If this option is set, then a message-list specifier in the form ``/x:y'' +will expand to all messages containing the substring ``y'' in the header +field ``x''. The string search is case insensitive. +.It Ar verbose +Setting the option +.Ar verbose +is the same as using the +.Fl v +flag on the command line. +When mail runs in verbose mode, +the actual delivery of messages is displayed on the user's +terminal. +.El +.Ss Option String Values +.Bl -tag -width Va +.It Ev EDITOR +Pathname of the text editor to use in the +.Ic edit +command and +.Ic \&~e +escape. +If not defined, then a default editor is used. +.It Ev LISTER +Pathname of the directory lister to use in the +.Ic folders +command. +Default is +.Pa /bin/ls . +.It Ev PAGER +Pathname of the program to use in the +.Ic more +command or when +.Ic crt +variable is set. +The default paginator +.Xr more 1 +is used if this option is not defined. +.It Ev SHELL +Pathname of the shell to use in the +.Ic \&! +command and the +.Ic \&~! +escape. +A default shell is used if this option is +not defined. +.It Ev VISUAL +Pathname of the text editor to use in the +.Ic visual +command and +.Ic \&~v +escape. +.It Va crt +The valued option +.Va crt +is used as a threshold to determine how long a message must +be before +.Ev PAGER +is used to read it. +If +.Va crt +is set without a value, +then the height of the terminal screen stored in the system +is used to compute the threshold (see +.Xr stty 1 ) . +.It Ar escape +If defined, the first character of this option gives the character to +use in the place of ~ to denote escapes. +.It Ar folder +The name of the directory to use for storing folders of +messages. +If this name begins with a `/', +.Nm mail +considers it to be an absolute pathname; otherwise, the +folder directory is found relative to your home directory. +.It Ev MBOX +The name of the +.Ar mbox +file. +It can be the name of a folder. +The default is +.Dq Li mbox +in the user's home directory. +.It Ar record +If defined, gives the pathname of the file used to record all outgoing +mail. +If not defined, then outgoing mail is not so saved. +.It Ar indentprefix +String used by the ``~m'' tilde escape for indenting messages, in place of +the normal tab character (^I). +Be sure to quote the value if it contains +spaces or tabs. +.It Ar toplines +If defined, gives the number of lines of a message to be printed out +with the +.Ic top +command; normally, the first five lines are printed. +.El +.Sh ENVIRONMENT +.Nm Mail +utilizes the +.Ev HOME +and +.Ev USER +environment variables. +.Sh FILES +.Bl -tag -width /usr/share/misc/Mail.help* -compact +.It Pa /var/spool/mail/* +Post office. +.It ~/mbox +User's old mail. +.It ~/.mailrc +File giving initial mail commands. +.It Pa /tmp/R* +Temporary files. +.It Pa /usr/share/misc/Mail.help* +Help files. +.It Pa /usr/share/misc/Mail.rc +System initialization file. +.El +.Sh SEE ALSO +.Xr fmt 1 , +.Xr newaliases 1 , +.Xr vacation 1 , +.Xr aliases 5 , +.Xr mailaddr 7 , +.Xr sendmail 8 +and +.Rs +.%T "The Mail Reference Manual" . +.Re +.Sh HISTORY +A +.Nm mail +command +appeared in +.At v6 . +This man page is derived from +.%T "The Mail Reference Manual" +originally written by Kurt Shoens. +.Sh BUGS +There are some flags that are not documented here. +Most are +not useful to the general user. +.Pp +Usually, +.Nm mail +is just a link to +.Nm Mail , +which can be confusing. diff --git a/usr.bin/mail/main.c b/usr.bin/mail/main.c new file mode 100644 index 0000000..1e1579b --- /dev/null +++ b/usr.bin/mail/main.c @@ -0,0 +1,296 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * Startup -- interface with user. + */ + +jmp_buf hdrjmp; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int i; + struct name *to, *cc, *bcc, *smopts; + char *subject; + char *ef; + char nosrc = 0; + void hdrstop(); + sig_t prevint; + void sigchild(); + + /* + * Set up a reasonable environment. + * Figure out whether we are being run interactively, + * start the SIGCHLD catcher, and so forth. + */ + (void) signal(SIGCHLD, sigchild); + if (isatty(0)) + assign("interactive", ""); + image = -1; + /* + * Now, determine how we are being used. + * We successively pick off - flags. + * If there is anything left, it is the base of the list + * of users to mail to. Argp will be set to point to the + * first of these users. + */ + ef = NOSTR; + to = NIL; + cc = NIL; + bcc = NIL; + smopts = NIL; + subject = NOSTR; + while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != EOF) { + switch (i) { + case 'T': + /* + * Next argument is temp file to write which + * articles have been read/deleted for netnews. + */ + Tflag = optarg; + if ((i = creat(Tflag, 0600)) < 0) { + perror(Tflag); + exit(1); + } + close(i); + break; + case 'u': + /* + * Next argument is person to pretend to be. + */ + myname = optarg; + break; + case 'i': + /* + * User wants to ignore interrupts. + * Set the variable "ignore" + */ + assign("ignore", ""); + break; + case 'd': + debug++; + break; + case 's': + /* + * Give a subject field for sending from + * non terminal + */ + subject = optarg; + break; + case 'f': + /* + * User is specifying file to "edit" with Mail, + * as opposed to reading system mailbox. + * If no argument is given after -f, we read his + * mbox file. + * + * getopt() can't handle optional arguments, so here + * is an ugly hack to get around it. + */ + if ((argv[optind]) && (argv[optind][0] != '-')) + ef = argv[optind++]; + else + ef = "&"; + break; + case 'n': + /* + * User doesn't want to source /usr/lib/Mail.rc + */ + nosrc++; + break; + case 'N': + /* + * Avoid initial header printing. + */ + assign("noheader", ""); + break; + case 'v': + /* + * Send mailer verbose flag + */ + assign("verbose", ""); + break; + case 'I': + /* + * We're interactive + */ + assign("interactive", ""); + break; + case 'c': + /* + * Get Carbon Copy Recipient list + */ + cc = cat(cc, nalloc(optarg, GCC)); + break; + case 'b': + /* + * Get Blind Carbon Copy Recipient list + */ + bcc = cat(bcc, nalloc(optarg, GBCC)); + break; + case '?': + fputs("\ +Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ + [- sendmail-options ...]\n\ + mail [-iInNv] -f [name]\n\ + mail [-iInNv] [-u user]\n", + stderr); + exit(1); + } + } + for (i = optind; (argv[i]) && (*argv[i] != '-'); i++) + to = cat(to, nalloc(argv[i], GTO)); + for (; argv[i]; i++) + smopts = cat(smopts, nalloc(argv[i], 0)); + /* + * Check for inconsistent arguments. + */ + if (to == NIL && (subject != NOSTR || cc != NIL || bcc != NIL)) { + fputs("You must specify direct recipients with -s, -c, or -b.\n", stderr); + exit(1); + } + if (ef != NOSTR && to != NIL) { + fprintf(stderr, "Cannot give -f and people to send to.\n"); + exit(1); + } + tinit(); + setscreensize(); + input = stdin; + rcvmode = !to; + spreserve(); + if (!nosrc) + load(_PATH_MASTER_RC); + /* + * Expand returns a savestr, but load only uses the file name + * for fopen, so it's safe to do this. + */ + load(expand("~/.mailrc")); + if (!rcvmode) { + mail(to, cc, bcc, smopts, subject); + /* + * why wait? + */ + exit(senderr); + } + /* + * Ok, we are reading mail. + * Decide whether we are editing a mailbox or reading + * the system mailbox, and open up the right stuff. + */ + if (ef == NOSTR) + ef = "%"; + if (setfile(ef) < 0) + exit(1); /* error already reported */ + if (setjmp(hdrjmp) == 0) { + extern char *version; + + if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN) + signal(SIGINT, hdrstop); + if (value("quiet") == NOSTR) + printf("Mail version %s. Type ? for help.\n", + version); + announce(); + fflush(stdout); + signal(SIGINT, prevint); + } + commands(); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + quit(); + exit(0); +} + +/* + * Interrupt printing of the headers. + */ +void +hdrstop(signo) + int signo; +{ + + fflush(stdout); + fprintf(stderr, "\nInterrupt\n"); + longjmp(hdrjmp, 1); +} + +/* + * Compute what the screen size for printing headers should be. + * We use the following algorithm for the height: + * If baud rate < 1200, use 9 + * If baud rate = 1200, use 14 + * If baud rate > 1200, use 24 or ws_row + * Width is either 80 or ws_col; + */ +void +setscreensize() +{ + struct sgttyb tbuf; + struct winsize ws; + + if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0) + ws.ws_col = ws.ws_row = 0; + if (ioctl(1, TIOCGETP, &tbuf) < 0) + tbuf.sg_ospeed = B9600; + if (tbuf.sg_ospeed < B1200) + screenheight = 9; + else if (tbuf.sg_ospeed == B1200) + screenheight = 14; + else if (ws.ws_row != 0) + screenheight = ws.ws_row; + else + screenheight = 24; + if ((realscreenheight = ws.ws_row) == 0) + realscreenheight = 24; + if ((screenwidth = ws.ws_col) == 0) + screenwidth = 80; +} diff --git a/usr.bin/mail/misc/mail.help b/usr.bin/mail/misc/mail.help new file mode 100644 index 0000000..d5858c5 --- /dev/null +++ b/usr.bin/mail/misc/mail.help @@ -0,0 +1,23 @@ + Mail Commands +t type messages +n goto and type next message +e edit messages +f give head lines of messages +d delete messages +s file append messages to file +u undelete messages +R reply to message senders +r reply to message senders and all recipients +pre make messages go back to /usr/spool/mail +m mail to specific users +q quit, saving unresolved messages in mbox +x quit, do not remove system mailbox +h print out active message headers +! shell escape +cd [directory] chdir to directory or home if none given + +A consists of integers, ranges of same, or user names separated +by spaces. If omitted, Mail uses the last message typed. + +A consists of user names or aliases separated by spaces. +Aliases are defined in .mailrc in your home directory. diff --git a/usr.bin/mail/misc/mail.rc b/usr.bin/mail/misc/mail.rc new file mode 100644 index 0000000..90e937a --- /dev/null +++ b/usr.bin/mail/misc/mail.rc @@ -0,0 +1,2 @@ +set append dot save +ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via diff --git a/usr.bin/mail/misc/mail.tildehelp b/usr.bin/mail/misc/mail.tildehelp new file mode 100644 index 0000000..0b1ab13 --- /dev/null +++ b/usr.bin/mail/misc/mail.tildehelp @@ -0,0 +1,22 @@ +----------------------------------------------------------- +The following ~ escapes are defined: +~~ Quote a single tilde +~b users Add users to "blind" cc list +~c users Add users to cc list +~d Read in dead.letter +~e Edit the message buffer +~f messages Read in messages +~F messages Same as ~f, but keep all header lines +~h Prompt for to list, subject and cc list +~r file Read a file into the message buffer +~p Print the message buffer +~m messages Read in messages, right shifted by a tab +~M messages Same as ~m, but keep all header lines +~s subject Set subject +~t users Add users to to list +~v Invoke display editor on message +~w file Write message onto file. +~? Print this message +~!command Invoke the shell +~|command Pipe the message through the command +----------------------------------------------------------- diff --git a/usr.bin/mail/names.c b/usr.bin/mail/names.c new file mode 100644 index 0000000..b2f8cfe --- /dev/null +++ b/usr.bin/mail/names.c @@ -0,0 +1,694 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Handle name lists. + */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Allocate a single element of a name list, + * initialize its name field to the passed + * name and return it. + */ +struct name * +nalloc(str, ntype) + char str[]; + int ntype; +{ + register struct name *np; + + np = (struct name *) salloc(sizeof *np); + np->n_flink = NIL; + np->n_blink = NIL; + np->n_type = ntype; + np->n_name = savestr(str); + return(np); +} + +/* + * Find the tail of a list and return it. + */ +struct name * +tailof(name) + struct name *name; +{ + register struct name *np; + + np = name; + if (np == NIL) + return(NIL); + while (np->n_flink != NIL) + np = np->n_flink; + return(np); +} + +/* + * Extract a list of names from a line, + * and make a list of names from it. + * Return the list or NIL if none found. + */ +struct name * +extract(line, ntype) + char line[]; + int ntype; +{ + register char *cp; + register struct name *top, *np, *t; + char nbuf[BUFSIZ]; + + if (line == NOSTR || *line == '\0') + return NIL; + top = NIL; + np = NIL; + cp = line; + while ((cp = yankword(cp, nbuf)) != NOSTR) { + t = nalloc(nbuf, ntype); + if (top == NIL) + top = t; + else + np->n_flink = t; + t->n_blink = np; + np = t; + } + return top; +} + +/* + * Turn a list of names into a string of the same names. + */ +char * +detract(np, ntype) + register struct name *np; + int ntype; +{ + register int s; + register char *cp, *top; + register struct name *p; + register int comma; + + comma = ntype & GCOMMA; + if (np == NIL) + return(NOSTR); + ntype &= ~GCOMMA; + s = 0; + if (debug && comma) + fprintf(stderr, "detract asked to insert commas\n"); + for (p = np; p != NIL; p = p->n_flink) { + if (ntype && (p->n_type & GMASK) != ntype) + continue; + s += strlen(p->n_name) + 1; + if (comma) + s++; + } + if (s == 0) + return(NOSTR); + s += 2; + top = salloc(s); + cp = top; + for (p = np; p != NIL; p = p->n_flink) { + if (ntype && (p->n_type & GMASK) != ntype) + continue; + cp = copy(p->n_name, cp); + if (comma && p->n_flink != NIL) + *cp++ = ','; + *cp++ = ' '; + } + *--cp = 0; + if (comma && *--cp == ',') + *cp = 0; + return(top); +} + +/* + * Grab a single word (liberal word) + * Throw away things between ()'s, and take anything between <>. + */ +char * +yankword(ap, wbuf) + char *ap, wbuf[]; +{ + register char *cp, *cp2; + + cp = ap; + for (;;) { + if (*cp == '\0') + return NOSTR; + if (*cp == '(') { + register int nesting = 0; + + while (*cp != '\0') { + switch (*cp++) { + case '(': + nesting++; + break; + case ')': + --nesting; + break; + } + if (nesting <= 0) + break; + } + } else if (*cp == ' ' || *cp == '\t' || *cp == ',') + cp++; + else + break; + } + if (*cp == '<') + for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';) + ; + else + for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++) + ; + *cp2 = '\0'; + return cp; +} + +/* + * For each recipient in the passed name list with a / + * in the name, append the message to the end of the named file + * and remove him from the recipient list. + * + * Recipients whose name begins with | are piped through the given + * program and removed. + */ +struct name * +outof(names, fo, hp) + struct name *names; + FILE *fo; + struct header *hp; +{ + register int c; + register struct name *np, *top; + time_t now, time(); + char *date, *fname, *ctime(); + FILE *fout, *fin; + int ispipe; + extern char tempEdit[]; + + top = names; + np = names; + (void) time(&now); + date = ctime(&now); + while (np != NIL) { + if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { + np = np->n_flink; + continue; + } + ispipe = np->n_name[0] == '|'; + if (ispipe) + fname = np->n_name+1; + else + fname = expand(np->n_name); + + /* + * See if we have copied the complete message out yet. + * If not, do so. + */ + + if (image < 0) { + if ((fout = Fopen(tempEdit, "a")) == NULL) { + perror(tempEdit); + senderr++; + goto cant; + } + image = open(tempEdit, 2); + (void) unlink(tempEdit); + if (image < 0) { + perror(tempEdit); + senderr++; + (void) Fclose(fout); + goto cant; + } + (void) fcntl(image, F_SETFD, 1); + fprintf(fout, "From %s %s", myname, date); + puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); + while ((c = getc(fo)) != EOF) + (void) putc(c, fout); + rewind(fo); + (void) putc('\n', fout); + (void) fflush(fout); + if (ferror(fout)) + perror(tempEdit); + (void) Fclose(fout); + } + + /* + * Now either copy "image" to the desired file + * or give it as the standard input to the desired + * program as appropriate. + */ + + if (ispipe) { + int pid; + char *shell; + + /* + * XXX + * We can't really reuse the same image file, + * because multiple piped recipients will + * share the same lseek location and trample + * on one another. + */ + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + pid = start_command(shell, sigmask(SIGHUP)| + sigmask(SIGINT)|sigmask(SIGQUIT), + image, -1, "-c", fname, NOSTR); + if (pid < 0) { + senderr++; + goto cant; + } + free_child(pid); + } else { + int f; + if ((fout = Fopen(fname, "a")) == NULL) { + perror(fname); + senderr++; + goto cant; + } + if ((f = dup(image)) < 0) { + perror("dup"); + fin = NULL; + } else + fin = Fdopen(f, "r"); + if (fin == NULL) { + fprintf(stderr, "Can't reopen image\n"); + (void) Fclose(fout); + senderr++; + goto cant; + } + rewind(fin); + while ((c = getc(fin)) != EOF) + (void) putc(c, fout); + if (ferror(fout)) + senderr++, perror(fname); + (void) Fclose(fout); + (void) Fclose(fin); + } +cant: + /* + * In days of old we removed the entry from the + * the list; now for sake of header expansion + * we leave it in and mark it as deleted. + */ + np->n_type |= GDEL; + np = np->n_flink; + } + if (image >= 0) { + (void) close(image); + image = -1; + } + return(top); +} + +/* + * Determine if the passed address is a local "send to file" address. + * If any of the network metacharacters precedes any slashes, it can't + * be a filename. We cheat with .'s to allow path names like ./... + */ +int +isfileaddr(name) + char *name; +{ + register char *cp; + + if (*name == '+') + return 1; + for (cp = name; *cp; cp++) { + if (*cp == '!' || *cp == '%' || *cp == '@') + return 0; + if (*cp == '/') + return 1; + } + return 0; +} + +/* + * Map all of the aliased users in the invoker's mailrc + * file and insert them into the list. + * Changed after all these months of service to recursively + * expand names (2/14/80). + */ + +struct name * +usermap(names) + struct name *names; +{ + register struct name *new, *np, *cp; + struct grouphead *gh; + register int metoo; + + new = NIL; + np = names; + metoo = (value("metoo") != NOSTR); + while (np != NIL) { + if (np->n_name[0] == '\\') { + cp = np->n_flink; + new = put(new, np); + np = cp; + continue; + } + gh = findgroup(np->n_name); + cp = np->n_flink; + if (gh != NOGRP) + new = gexpand(new, gh, metoo, np->n_type); + else + new = put(new, np); + np = cp; + } + return(new); +} + +/* + * Recursively expand a group name. We limit the expansion to some + * fixed level to keep things from going haywire. + * Direct recursion is not expanded for convenience. + */ + +struct name * +gexpand(nlist, gh, metoo, ntype) + struct name *nlist; + struct grouphead *gh; + int metoo, ntype; +{ + struct group *gp; + struct grouphead *ngh; + struct name *np; + static int depth; + char *cp; + + if (depth > MAXEXP) { + printf("Expanding alias to depth larger than %d\n", MAXEXP); + return(nlist); + } + depth++; + for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { + cp = gp->ge_name; + if (*cp == '\\') + goto quote; + if (strcmp(cp, gh->g_name) == 0) + goto quote; + if ((ngh = findgroup(cp)) != NOGRP) { + nlist = gexpand(nlist, ngh, metoo, ntype); + continue; + } +quote: + np = nalloc(cp, ntype); + /* + * At this point should allow to expand + * to self if only person in group + */ + if (gp == gh->g_list && gp->ge_link == NOGE) + goto skip; + if (!metoo && strcmp(cp, myname) == 0) + np->n_type |= GDEL; +skip: + nlist = put(nlist, np); + } + depth--; + return(nlist); +} + +/* + * Concatenate the two passed name lists, return the result. + */ +struct name * +cat(n1, n2) + struct name *n1, *n2; +{ + register struct name *tail; + + if (n1 == NIL) + return(n2); + if (n2 == NIL) + return(n1); + tail = tailof(n1); + tail->n_flink = n2; + n2->n_blink = tail; + return(n1); +} + +/* + * Unpack the name list onto a vector of strings. + * Return an error if the name list won't fit. + */ +char ** +unpack(np) + struct name *np; +{ + register char **ap, **top; + register struct name *n; + int t, extra, metoo, verbose; + + n = np; + if ((t = count(n)) == 0) + panic("No names to unpack"); + /* + * Compute the number of extra arguments we will need. + * We need at least two extra -- one for "mail" and one for + * the terminating 0 pointer. Additional spots may be needed + * to pass along -f to the host mailer. + */ + extra = 2; + extra++; + metoo = value("metoo") != NOSTR; + if (metoo) + extra++; + verbose = value("verbose") != NOSTR; + if (verbose) + extra++; + top = (char **) salloc((t + extra) * sizeof *top); + ap = top; + *ap++ = "send-mail"; + *ap++ = "-i"; + if (metoo) + *ap++ = "-m"; + if (verbose) + *ap++ = "-v"; + for (; n != NIL; n = n->n_flink) + if ((n->n_type & GDEL) == 0) + *ap++ = n->n_name; + *ap = NOSTR; + return(top); +} + +/* + * Remove all of the duplicates from the passed name list by + * insertion sorting them, then checking for dups. + * Return the head of the new list. + */ +struct name * +elide(names) + struct name *names; +{ + register struct name *np, *t, *new; + struct name *x; + + if (names == NIL) + return(NIL); + new = names; + np = names; + np = np->n_flink; + if (np != NIL) + np->n_blink = NIL; + new->n_flink = NIL; + while (np != NIL) { + t = new; + while (strcasecmp(t->n_name, np->n_name) < 0) { + if (t->n_flink == NIL) + break; + t = t->n_flink; + } + + /* + * If we ran out of t's, put the new entry after + * the current value of t. + */ + + if (strcasecmp(t->n_name, np->n_name) < 0) { + t->n_flink = np; + np->n_blink = t; + t = np; + np = np->n_flink; + t->n_flink = NIL; + continue; + } + + /* + * Otherwise, put the new entry in front of the + * current t. If at the front of the list, + * the new guy becomes the new head of the list. + */ + + if (t == new) { + t = np; + np = np->n_flink; + t->n_flink = new; + new->n_blink = t; + t->n_blink = NIL; + new = t; + continue; + } + + /* + * The normal case -- we are inserting into the + * middle of the list. + */ + + x = np; + np = np->n_flink; + x->n_flink = t; + x->n_blink = t->n_blink; + t->n_blink->n_flink = x; + t->n_blink = x; + } + + /* + * Now the list headed up by new is sorted. + * Go through it and remove duplicates. + */ + + np = new; + while (np != NIL) { + t = np; + while (t->n_flink != NIL && + strcasecmp(np->n_name, t->n_flink->n_name) == 0) + t = t->n_flink; + if (t == np || t == NIL) { + np = np->n_flink; + continue; + } + + /* + * Now t points to the last entry with the same name + * as np. Make np point beyond t. + */ + + np->n_flink = t->n_flink; + if (t->n_flink != NIL) + t->n_flink->n_blink = np; + np = np->n_flink; + } + return(new); +} + +/* + * Put another node onto a list of names and return + * the list. + */ +struct name * +put(list, node) + struct name *list, *node; +{ + node->n_flink = list; + node->n_blink = NIL; + if (list != NIL) + list->n_blink = node; + return(node); +} + +/* + * Determine the number of undeleted elements in + * a name list and return it. + */ +int +count(np) + register struct name *np; +{ + register int c; + + for (c = 0; np != NIL; np = np->n_flink) + if ((np->n_type & GDEL) == 0) + c++; + return c; +} + +/* + * Delete the given name from a namelist. + */ +struct name * +delname(np, name) + register struct name *np; + char name[]; +{ + register struct name *p; + + for (p = np; p != NIL; p = p->n_flink) + if (strcasecmp(p->n_name, name) == 0) { + if (p->n_blink == NIL) { + if (p->n_flink != NIL) + p->n_flink->n_blink = NIL; + np = p->n_flink; + continue; + } + if (p->n_flink == NIL) { + if (p->n_blink != NIL) + p->n_blink->n_flink = NIL; + continue; + } + p->n_blink->n_flink = p->n_flink; + p->n_flink->n_blink = p->n_blink; + } + return np; +} + +/* + * Pretty print a name list + * Uncomment it if you need it. + */ + +/* +void +prettyprint(name) + struct name *name; +{ + register struct name *np; + + np = name; + while (np != NIL) { + fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); + np = np->n_flink; + } + fprintf(stderr, "\n"); +} +*/ diff --git a/usr.bin/mail/pathnames.h b/usr.bin/mail/pathnames.h new file mode 100644 index 0000000..13a7672 --- /dev/null +++ b/usr.bin/mail/pathnames.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_EX "/usr/bin/ex" +#define _PATH_HELP "/usr/share/misc/mail.help" +#define _PATH_TILDE "/usr/share/misc/mail.tildehelp" +#define _PATH_MASTER_RC "/etc/mail.rc" +#define _PATH_MORE "/usr/bin/more" diff --git a/usr.bin/mail/popen.c b/usr.bin/mail/popen.c new file mode 100644 index 0000000..467d24a --- /dev/null +++ b/usr.bin/mail/popen.c @@ -0,0 +1,373 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include +#include "extern.h" + +#define READ 0 +#define WRITE 1 + +struct fp { + FILE *fp; + int pipe; + int pid; + struct fp *link; +}; +static struct fp *fp_head; + +struct child { + int pid; + char done; + char free; + union wait status; + struct child *link; +}; +static struct child *child; +static struct child *findchild __P((int)); +static void delchild __P((struct child *)); + +FILE * +Fopen(file, mode) + char *file, *mode; +{ + FILE *fp; + + if ((fp = fopen(file, mode)) != NULL) { + register_file(fp, 0, 0); + (void) fcntl(fileno(fp), F_SETFD, 1); + } + return fp; +} + +FILE * +Fdopen(fd, mode) + int fd; + char *mode; +{ + FILE *fp; + + if ((fp = fdopen(fd, mode)) != NULL) { + register_file(fp, 0, 0); + (void) fcntl(fileno(fp), F_SETFD, 1); + } + return fp; +} + +int +Fclose(fp) + FILE *fp; +{ + unregister_file(fp); + return fclose(fp); +} + +FILE * +Popen(cmd, mode) + char *cmd; + char *mode; +{ + int p[2]; + int myside, hisside, fd0, fd1; + int pid; + FILE *fp; + + if (pipe(p) < 0) + return NULL; + (void) fcntl(p[READ], F_SETFD, 1); + (void) fcntl(p[WRITE], F_SETFD, 1); + if (*mode == 'r') { + myside = p[READ]; + fd0 = -1; + hisside = fd1 = p[WRITE]; + } else { + myside = p[WRITE]; + hisside = fd0 = p[READ]; + fd1 = -1; + } + if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { + close(p[READ]); + close(p[WRITE]); + return NULL; + } + (void) close(hisside); + if ((fp = fdopen(myside, mode)) != NULL) + register_file(fp, 1, pid); + return fp; +} + +int +Pclose(ptr) + FILE *ptr; +{ + int i; + int omask; + + i = file_pid(ptr); + unregister_file(ptr); + (void) fclose(ptr); + omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); + i = wait_child(i); + sigsetmask(omask); + return i; +} + +void +close_all_files() +{ + + while (fp_head) + if (fp_head->pipe) + (void) Pclose(fp_head->fp); + else + (void) Fclose(fp_head->fp); +} + +void +register_file(fp, pipe, pid) + FILE *fp; + int pipe, pid; +{ + struct fp *fpp; + + if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) + panic("Out of memory"); + fpp->fp = fp; + fpp->pipe = pipe; + fpp->pid = pid; + fpp->link = fp_head; + fp_head = fpp; +} + +void +unregister_file(fp) + FILE *fp; +{ + struct fp **pp, *p; + + for (pp = &fp_head; p = *pp; pp = &p->link) + if (p->fp == fp) { + *pp = p->link; + free((char *) p); + return; + } + panic("Invalid file pointer"); +} + +file_pid(fp) + FILE *fp; +{ + struct fp *p; + + for (p = fp_head; p; p = p->link) + if (p->fp == fp) + return (p->pid); + panic("Invalid file pointer"); + /*NOTREACHED*/ +} + +/* + * Run a command without a shell, with optional arguments and splicing + * of stdin and stdout. The command name can be a sequence of words. + * Signals must be handled by the caller. + * "Mask" contains the signals to ignore in the new process. + * SIGINT is enabled unless it's in the mask. + */ +/*VARARGS4*/ +int +run_command(cmd, mask, infd, outfd, a0, a1, a2) + char *cmd; + int mask, infd, outfd; + char *a0, *a1, *a2; +{ + int pid; + + if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) + return -1; + return wait_command(pid); +} + +/*VARARGS4*/ +int +start_command(cmd, mask, infd, outfd, a0, a1, a2) + char *cmd; + int mask, infd, outfd; + char *a0, *a1, *a2; +{ + int pid; + + if ((pid = vfork()) < 0) { + perror("fork"); + return -1; + } + if (pid == 0) { + char *argv[100]; + int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); + + if ((argv[i++] = a0) != NOSTR && + (argv[i++] = a1) != NOSTR && + (argv[i++] = a2) != NOSTR) + argv[i] = NOSTR; + prepare_child(mask, infd, outfd); + execvp(argv[0], argv); + perror(argv[0]); + _exit(1); + } + return pid; +} + +void +prepare_child(mask, infd, outfd) + int mask, infd, outfd; +{ + int i; + + /* + * All file descriptors other than 0, 1, and 2 are supposed to be + * close-on-exec. + */ + if (infd >= 0) + dup2(infd, 0); + if (outfd >= 0) + dup2(outfd, 1); + for (i = 1; i <= NSIG; i++) + if (mask & sigmask(i)) + (void) signal(i, SIG_IGN); + if ((mask & sigmask(SIGINT)) == 0) + (void) signal(SIGINT, SIG_DFL); + (void) sigsetmask(0); +} + +int +wait_command(pid) + int pid; +{ + + if (wait_child(pid) < 0) { + printf("Fatal error in process.\n"); + return -1; + } + return 0; +} + +static struct child * +findchild(pid) + int pid; +{ + register struct child **cpp; + + for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; + cpp = &(*cpp)->link) + ; + if (*cpp == NULL) { + *cpp = (struct child *) malloc(sizeof (struct child)); + (*cpp)->pid = pid; + (*cpp)->done = (*cpp)->free = 0; + (*cpp)->link = NULL; + } + return *cpp; +} + +static void +delchild(cp) + register struct child *cp; +{ + register struct child **cpp; + + for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) + ; + *cpp = cp->link; + free((char *) cp); +} + +void +sigchild(signo) + int signo; +{ + int pid; + union wait status; + register struct child *cp; + + while ((pid = + wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { + cp = findchild(pid); + if (cp->free) + delchild(cp); + else { + cp->done = 1; + cp->status = status; + } + } +} + +union wait wait_status; + +/* + * Wait for a specific child to die. + */ +int +wait_child(pid) + int pid; +{ + int mask = sigblock(sigmask(SIGCHLD)); + register struct child *cp = findchild(pid); + + while (!cp->done) + sigpause(mask); + wait_status = cp->status; + delchild(cp); + sigsetmask(mask); + return wait_status.w_status ? -1 : 0; +} + +/* + * Mark a child as don't care. + */ +void +free_child(pid) + int pid; +{ + int mask = sigblock(sigmask(SIGCHLD)); + register struct child *cp = findchild(pid); + + if (cp->done) + delchild(cp); + else + cp->free = 1; + sigsetmask(mask); +} diff --git a/usr.bin/mail/quit.c b/usr.bin/mail/quit.c new file mode 100644 index 0000000..05e708f --- /dev/null +++ b/usr.bin/mail/quit.c @@ -0,0 +1,491 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)quit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Rcv -- receive mail rationally. + * + * Termination processing. + */ + +/* + * The "quit" command. + */ +int +quitcmd() +{ + /* + * If we are sourcing, then return 1 so execute() can handle it. + * Otherwise, return -1 to abort command loop. + */ + if (sourcing) + return 1; + return -1; +} + +/* + * Save all of the undetermined messages at the top of "mbox" + * Save all untouched messages back in the system mailbox. + * Remove the system mailbox, if none saved there. + */ +void +quit() +{ + int mcount, p, modify, autohold, anystat, holdbit, nohold; + FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf; + register struct message *mp; + register int c; + extern char tempQuit[], tempResid[]; + struct stat minfo; + char *mbox; + + /* + * If we are read only, we can't do anything, + * so just return quickly. + */ + if (readonly) + return; + /* + * If editing (not reading system mail box), then do the work + * in edstop() + */ + if (edit) { + edstop(); + return; + } + + /* + * See if there any messages to save in mbox. If no, we + * can save copying mbox to /tmp and back. + * + * Check also to see if any files need to be preserved. + * Delete all untouched messages to keep them out of mbox. + * If all the messages are to be preserved, just exit with + * a message. + */ + + fbuf = Fopen(mailname, "r"); + if (fbuf == NULL) + goto newmail; + flock(fileno(fbuf), LOCK_EX); + rbuf = NULL; + if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) { + printf("New mail has arrived.\n"); + rbuf = Fopen(tempResid, "w"); + if (rbuf == NULL || fbuf == NULL) + goto newmail; +#ifdef APPEND + fseek(fbuf, (long)mailsize, 0); + while ((c = getc(fbuf)) != EOF) + (void) putc(c, rbuf); +#else + p = minfo.st_size - mailsize; + while (p-- > 0) { + c = getc(fbuf); + if (c == EOF) + goto newmail; + (void) putc(c, rbuf); + } +#endif + Fclose(rbuf); + if ((rbuf = Fopen(tempResid, "r")) == NULL) + goto newmail; + rm(tempResid); + } + + /* + * Adjust the message flags in each message. + */ + + anystat = 0; + autohold = value("hold") != NOSTR; + holdbit = autohold ? MPRESERVE : MBOX; + nohold = MBOX|MSAVED|MDELETED|MPRESERVE; + if (value("keepsave") != NOSTR) + nohold &= ~MSAVED; + for (mp = &message[0]; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) { + mp->m_flag &= ~MNEW; + mp->m_flag |= MSTATUS; + } + if (mp->m_flag & MSTATUS) + anystat++; + if ((mp->m_flag & MTOUCH) == 0) + mp->m_flag |= MPRESERVE; + if ((mp->m_flag & nohold) == 0) + mp->m_flag |= holdbit; + } + modify = 0; + if (Tflag != NOSTR) { + if ((readstat = Fopen(Tflag, "w")) == NULL) + Tflag = NOSTR; + } + for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MBOX) + c++; + if (mp->m_flag & MPRESERVE) + p++; + if (mp->m_flag & MODIFY) + modify++; + if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { + char *id; + + if ((id = hfield("article-id", mp)) != NOSTR) + fprintf(readstat, "%s\n", id); + } + } + if (Tflag != NOSTR) + Fclose(readstat); + if (p == msgCount && !modify && !anystat) { + printf("Held %d message%s in %s\n", + p, p == 1 ? "" : "s", mailname); + Fclose(fbuf); + return; + } + if (c == 0) { + if (p != 0) { + writeback(rbuf); + Fclose(fbuf); + return; + } + goto cream; + } + + /* + * Create another temporary file and copy user's mbox file + * darin. If there is no mbox, copy nothing. + * If he has specified "append" don't copy his mailbox, + * just copy saveable entries at the end. + */ + + mbox = expand("&"); + mcount = c; + if (value("append") == NOSTR) { + if ((obuf = Fopen(tempQuit, "w")) == NULL) { + perror(tempQuit); + Fclose(fbuf); + return; + } + if ((ibuf = Fopen(tempQuit, "r")) == NULL) { + perror(tempQuit); + rm(tempQuit); + Fclose(obuf); + Fclose(fbuf); + return; + } + rm(tempQuit); + if ((abuf = Fopen(mbox, "r")) != NULL) { + while ((c = getc(abuf)) != EOF) + (void) putc(c, obuf); + Fclose(abuf); + } + if (ferror(obuf)) { + perror(tempQuit); + Fclose(ibuf); + Fclose(obuf); + Fclose(fbuf); + return; + } + Fclose(obuf); + close(creat(mbox, 0600)); + if ((obuf = Fopen(mbox, "r+")) == NULL) { + perror(mbox); + Fclose(ibuf); + Fclose(fbuf); + return; + } + } + if (value("append") != NOSTR) { + if ((obuf = Fopen(mbox, "a")) == NULL) { + perror(mbox); + Fclose(fbuf); + return; + } + fchmod(fileno(obuf), 0600); + } + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MBOX) + if (send(mp, obuf, saveignore, NOSTR) < 0) { + perror(mbox); + Fclose(ibuf); + Fclose(obuf); + Fclose(fbuf); + return; + } + + /* + * Copy the user's old mbox contents back + * to the end of the stuff we just saved. + * If we are appending, this is unnecessary. + */ + + if (value("append") == NOSTR) { + rewind(ibuf); + c = getc(ibuf); + while (c != EOF) { + (void) putc(c, obuf); + if (ferror(obuf)) + break; + c = getc(ibuf); + } + Fclose(ibuf); + fflush(obuf); + } + trunc(obuf); + if (ferror(obuf)) { + perror(mbox); + Fclose(obuf); + Fclose(fbuf); + return; + } + Fclose(obuf); + if (mcount == 1) + printf("Saved 1 message in mbox\n"); + else + printf("Saved %d messages in mbox\n", mcount); + + /* + * Now we are ready to copy back preserved files to + * the system mailbox, if any were requested. + */ + + if (p != 0) { + writeback(rbuf); + Fclose(fbuf); + return; + } + + /* + * Finally, remove his /usr/mail file. + * If new mail has arrived, copy it back. + */ + +cream: + if (rbuf != NULL) { + abuf = Fopen(mailname, "r+"); + if (abuf == NULL) + goto newmail; + while ((c = getc(rbuf)) != EOF) + (void) putc(c, abuf); + Fclose(rbuf); + trunc(abuf); + Fclose(abuf); + alter(mailname); + Fclose(fbuf); + return; + } + demail(); + Fclose(fbuf); + return; + +newmail: + printf("Thou hast new mail.\n"); + if (fbuf != NULL) + Fclose(fbuf); +} + +/* + * Preserve all the appropriate messages back in the system + * mailbox, and print a nice message indicated how many were + * saved. On any error, just return -1. Else return 0. + * Incorporate the any new mail that we found. + */ +int +writeback(res) + register FILE *res; +{ + register struct message *mp; + register int p, c; + FILE *obuf; + + p = 0; + if ((obuf = Fopen(mailname, "r+")) == NULL) { + perror(mailname); + return(-1); + } +#ifndef APPEND + if (res != NULL) + while ((c = getc(res)) != EOF) + (void) putc(c, obuf); +#endif + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) { + p++; + if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) { + perror(mailname); + Fclose(obuf); + return(-1); + } + } +#ifdef APPEND + if (res != NULL) + while ((c = getc(res)) != EOF) + (void) putc(c, obuf); +#endif + fflush(obuf); + trunc(obuf); + if (ferror(obuf)) { + perror(mailname); + Fclose(obuf); + return(-1); + } + if (res != NULL) + Fclose(res); + Fclose(obuf); + alter(mailname); + if (p == 1) + printf("Held 1 message in %s\n", mailname); + else + printf("Held %d messages in %s\n", p, mailname); + return(0); +} + +/* + * Terminate an editing session by attempting to write out the user's + * file from the temporary. Save any new stuff appended to the file. + */ +void +edstop() +{ + extern char *tmpdir; + register int gotcha, c; + register struct message *mp; + FILE *obuf, *ibuf, *readstat; + struct stat statb; + char tempname[30]; + char *mktemp(); + + if (readonly) + return; + holdsigs(); + if (Tflag != NOSTR) { + if ((readstat = Fopen(Tflag, "w")) == NULL) + Tflag = NOSTR; + } + for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) { + mp->m_flag &= ~MNEW; + mp->m_flag |= MSTATUS; + } + if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) + gotcha++; + if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { + char *id; + + if ((id = hfield("article-id", mp)) != NOSTR) + fprintf(readstat, "%s\n", id); + } + } + if (Tflag != NOSTR) + Fclose(readstat); + if (!gotcha || Tflag != NOSTR) + goto done; + ibuf = NULL; + if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { + strcpy(tempname, tmpdir); + strcat(tempname, "mboxXXXXXX"); + mktemp(tempname); + if ((obuf = Fopen(tempname, "w")) == NULL) { + perror(tempname); + relsesigs(); + reset(0); + } + if ((ibuf = Fopen(mailname, "r")) == NULL) { + perror(mailname); + Fclose(obuf); + rm(tempname); + relsesigs(); + reset(0); + } + fseek(ibuf, (long)mailsize, 0); + while ((c = getc(ibuf)) != EOF) + (void) putc(c, obuf); + Fclose(ibuf); + Fclose(obuf); + if ((ibuf = Fopen(tempname, "r")) == NULL) { + perror(tempname); + rm(tempname); + relsesigs(); + reset(0); + } + rm(tempname); + } + printf("\"%s\" ", mailname); + fflush(stdout); + if ((obuf = Fopen(mailname, "r+")) == NULL) { + perror(mailname); + relsesigs(); + reset(0); + } + trunc(obuf); + c = 0; + for (mp = &message[0]; mp < &message[msgCount]; mp++) { + if ((mp->m_flag & MDELETED) != 0) + continue; + c++; + if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) { + perror(mailname); + relsesigs(); + reset(0); + } + } + gotcha = (c == 0 && ibuf == NULL); + if (ibuf != NULL) { + while ((c = getc(ibuf)) != EOF) + (void) putc(c, obuf); + Fclose(ibuf); + } + fflush(obuf); + if (ferror(obuf)) { + perror(mailname); + relsesigs(); + reset(0); + } + Fclose(obuf); + if (gotcha) { + rm(mailname); + printf("removed\n"); + } else + printf("complete\n"); + fflush(stdout); + +done: + relsesigs(); +} diff --git a/usr.bin/mail/rcv.h b/usr.bin/mail/rcv.h new file mode 100644 index 0000000..6d78f36 --- /dev/null +++ b/usr.bin/mail/rcv.h @@ -0,0 +1,44 @@ +/* + * 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. + * + * @(#)rcv.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Mail -- a mail program + * + * This file is included by normal files which want both + * globals and declarations. + */ + +#include "def.h" +#include "glob.h" diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c new file mode 100644 index 0000000..c8b8fea --- /dev/null +++ b/usr.bin/mail/send.c @@ -0,0 +1,556 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Mail to others. + */ + +/* + * Send message described by the passed pointer to the + * passed output buffer. Return -1 on error. + * Adjust the status: field if need be. + * If doign is given, suppress ignored header fields. + * prefix is a string to prepend to each output line. + */ +int +send(mp, obuf, doign, prefix) + register struct message *mp; + FILE *obuf; + struct ignoretab *doign; + char *prefix; +{ + long count; + register FILE *ibuf; + char line[LINESIZE]; + int ishead, infld, ignoring, dostat, firstline; + register char *cp, *cp2; + register int c; + int length; + int prefixlen; + + /* + * Compute the prefix string, without trailing whitespace + */ + if (prefix != NOSTR) { + cp2 = 0; + for (cp = prefix; *cp; cp++) + if (*cp != ' ' && *cp != '\t') + cp2 = cp; + prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1; + } + ibuf = setinput(mp); + count = mp->m_size; + ishead = 1; + dostat = doign == 0 || !isign("status", doign); + infld = 0; + firstline = 1; + /* + * Process headers first + */ + while (count > 0 && ishead) { + if (fgets(line, LINESIZE, ibuf) == NULL) + break; + count -= length = strlen(line); + if (firstline) { + /* + * First line is the From line, so no headers + * there to worry about + */ + firstline = 0; + ignoring = doign == ignoreall; + } else if (line[0] == '\n') { + /* + * If line is blank, we've reached end of + * headers, so force out status: field + * and note that we are no longer in header + * fields + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ishead = 0; + ignoring = doign == ignoreall; + } else if (infld && (line[0] == ' ' || line[0] == '\t')) { + /* + * If this line is a continuation (via space or tab) + * of a previous header field, just echo it + * (unless the field should be ignored). + * In other words, nothing to do. + */ + } else { + /* + * Pick up the header field if we have one. + */ + for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) + ; + cp2 = --cp; + while (isspace(*cp++)) + ; + if (cp[-1] != ':') { + /* + * Not a header line, force out status: + * This happens in uucp style mail where + * there are no headers at all. + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + if (doign != ignoreall) + /* add blank line */ + (void) putc('\n', obuf); + ishead = 0; + ignoring = 0; + } else { + /* + * If it is an ignored field and + * we care about such things, skip it. + */ + *cp2 = 0; /* temporarily null terminate */ + if (doign && isign(line, doign)) + ignoring = 1; + else if ((line[0] == 's' || line[0] == 'S') && + strcasecmp(line, "status") == 0) { + /* + * If the field is "status," go compute + * and print the real Status: field + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ignoring = 1; + } else { + ignoring = 0; + *cp2 = c; /* restore */ + } + infld = 1; + } + } + if (!ignoring) { + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (prefix != NOSTR) + if (length > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, length, obuf); + if (ferror(obuf)) + return -1; + } + } + /* + * Copy out message body + */ + if (doign == ignoreall) + count--; /* skip final blank line */ + if (prefix != NOSTR) + while (count > 0) { + if (fgets(line, LINESIZE, ibuf) == NULL) { + c = 0; + break; + } + count -= c = strlen(line); + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (c > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, c, obuf); + if (ferror(obuf)) + return -1; + } + else + while (count > 0) { + c = count < LINESIZE ? count : LINESIZE; + if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) + break; + count -= c; + if (fwrite(line, sizeof *line, c, obuf) != c) + return -1; + } + if (doign == ignoreall && c > 0 && line[c - 1] != '\n') + /* no final blank line */ + if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) + return -1; + return 0; +} + +/* + * Output a reasonable looking status field. + */ +void +statusput(mp, obuf, prefix) + register struct message *mp; + FILE *obuf; + char *prefix; +{ + char statout[3]; + register char *cp = statout; + + if (mp->m_flag & MREAD) + *cp++ = 'R'; + if ((mp->m_flag & MNEW) == 0) + *cp++ = 'O'; + *cp = 0; + if (statout[0]) + fprintf(obuf, "%sStatus: %s\n", + prefix == NOSTR ? "" : prefix, statout); +} + +/* + * Interface between the argument list and the mail1 routine + * which does all the dirty work. + */ +int +mail(to, cc, bcc, smopts, subject) + struct name *to, *cc, *bcc, *smopts; + char *subject; +{ + struct header head; + + head.h_to = to; + head.h_subject = subject; + head.h_cc = cc; + head.h_bcc = bcc; + head.h_smopts = smopts; + mail1(&head, 0); + return(0); +} + + +/* + * Send mail to a bunch of user names. The interface is through + * the mail routine below. + */ +int +sendmail(str) + char *str; +{ + struct header head; + + head.h_to = extract(str, GTO); + head.h_subject = NOSTR; + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 0); + return(0); +} + +/* + * Mail a message on standard input to the people indicated + * in the passed header. (Internal interface). + */ +void +mail1(hp, printheaders) + struct header *hp; + int printheaders; +{ + char *cp; + int pid; + char **namelist; + struct name *to; + FILE *mtf; + + /* + * Collect user's mail from standard input. + * Get the result as mtf. + */ + if ((mtf = collect(hp, printheaders)) == NULL) + return; + if (value("interactive") != NOSTR) + if (value("askcc") != NOSTR) + grabh(hp, GCC); + else { + printf("EOT\n"); + (void) fflush(stdout); + } + if (fsize(mtf) == 0) + if (hp->h_subject == NOSTR) + printf("No message, no subject; hope that's ok\n"); + else + printf("Null message body; hope that's ok\n"); + /* + * Now, take the user names from the combined + * to and cc lists and do all the alias + * processing. + */ + senderr = 0; + to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); + if (to == NIL) { + printf("No recipients specified\n"); + senderr++; + } + /* + * Look through the recipient list for names with /'s + * in them which we write to as files directly. + */ + to = outof(to, mtf, hp); + if (senderr) + savedeadletter(mtf); + to = elide(to); + if (count(to) == 0) + goto out; + fixhead(hp, to); + if ((mtf = infix(hp, mtf)) == NULL) { + fprintf(stderr, ". . . message lost, sorry.\n"); + return; + } + namelist = unpack(cat(hp->h_smopts, to)); + if (debug) { + char **t; + + printf("Sendmail arguments:"); + for (t = namelist; *t != NOSTR; t++) + printf(" \"%s\"", *t); + printf("\n"); + goto out; + } + if ((cp = value("record")) != NOSTR) + (void) savemail(expand(cp), mtf); + /* + * Fork, set up the temporary mail file as standard + * input for "mail", and exec with the user list we generated + * far above. + */ + pid = fork(); + if (pid == -1) { + perror("fork"); + savedeadletter(mtf); + goto out; + } + if (pid == 0) { + prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| + sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), + fileno(mtf), -1); + if ((cp = value("sendmail")) != NOSTR) + cp = expand(cp); + else + cp = _PATH_SENDMAIL; + execv(cp, namelist); + perror(cp); + _exit(1); + } + if (value("verbose") != NOSTR) + (void) wait_child(pid); + else + free_child(pid); +out: + (void) Fclose(mtf); +} + +/* + * Fix the header by glopping all of the expanded names from + * the distribution list into the appropriate fields. + */ +void +fixhead(hp, tolist) + struct header *hp; + struct name *tolist; +{ + register struct name *np; + + hp->h_to = NIL; + hp->h_cc = NIL; + hp->h_bcc = NIL; + for (np = tolist; np != NIL; np = np->n_flink) + if ((np->n_type & GMASK) == GTO) + hp->h_to = + cat(hp->h_to, nalloc(np->n_name, np->n_type)); + else if ((np->n_type & GMASK) == GCC) + hp->h_cc = + cat(hp->h_cc, nalloc(np->n_name, np->n_type)); + else if ((np->n_type & GMASK) == GBCC) + hp->h_bcc = + cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); +} + +/* + * Prepend a header in front of the collected stuff + * and return the new file. + */ +FILE * +infix(hp, fi) + struct header *hp; + FILE *fi; +{ + extern char tempMail[]; + register FILE *nfo, *nfi; + register int c; + + if ((nfo = Fopen(tempMail, "w")) == NULL) { + perror(tempMail); + return(fi); + } + if ((nfi = Fopen(tempMail, "r")) == NULL) { + perror(tempMail); + (void) Fclose(nfo); + return(fi); + } + (void) rm(tempMail); + (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); + c = getc(fi); + while (c != EOF) { + (void) putc(c, nfo); + c = getc(fi); + } + if (ferror(fi)) { + perror("read"); + rewind(fi); + return(fi); + } + (void) fflush(nfo); + if (ferror(nfo)) { + perror(tempMail); + (void) Fclose(nfo); + (void) Fclose(nfi); + rewind(fi); + return(fi); + } + (void) Fclose(nfo); + (void) Fclose(fi); + rewind(nfi); + return(nfi); +} + +/* + * Dump the to, subject, cc header on the + * passed file buffer. + */ +int +puthead(hp, fo, w) + struct header *hp; + FILE *fo; + int w; +{ + register int gotcha; + + gotcha = 0; + if (hp->h_to != NIL && w & GTO) + fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; + if (hp->h_subject != NOSTR && w & GSUBJECT) + fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; + if (hp->h_cc != NIL && w & GCC) + fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; + if (hp->h_bcc != NIL && w & GBCC) + fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + if (gotcha && w & GNL) + (void) putc('\n', fo); + return(0); +} + +/* + * Format the given header line to not exceed 72 characters. + */ +void +fmt(str, np, fo, comma) + char *str; + register struct name *np; + FILE *fo; + int comma; +{ + register col, len; + + comma = comma ? 1 : 0; + col = strlen(str); + if (col) + fputs(str, fo); + for (; np != NIL; np = np->n_flink) { + if (np->n_flink == NIL) + comma = 0; + len = strlen(np->n_name); + col++; /* for the space */ + if (col + len + comma > 72 && col > 4) { + fputs("\n ", fo); + col = 4; + } else + putc(' ', fo); + fputs(np->n_name, fo); + if (comma) + putc(',', fo); + col += len + comma; + } + putc('\n', fo); +} + +/* + * Save the outgoing mail on the passed file. + */ + +/*ARGSUSED*/ +int +savemail(name, fi) + char name[]; + register FILE *fi; +{ + register FILE *fo; + char buf[BUFSIZ]; + register i; + time_t now, time(); + char *ctime(); + + if ((fo = Fopen(name, "a")) == NULL) { + perror(name); + return (-1); + } + (void) time(&now); + fprintf(fo, "From %s %s", myname, ctime(&now)); + while ((i = fread(buf, 1, sizeof buf, fi)) > 0) + (void) fwrite(buf, 1, i, fo); + (void) putc('\n', fo); + (void) fflush(fo); + if (ferror(fo)) + perror(name); + (void) Fclose(fo); + rewind(fi); + return (0); +} diff --git a/usr.bin/mail/strings.c b/usr.bin/mail/strings.c new file mode 100644 index 0000000..f27b959 --- /dev/null +++ b/usr.bin/mail/strings.c @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)strings.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * String allocation routines. + * Strings handed out here are reclaimed at the top of the command + * loop each time, so they need not be freed. + */ + +#include "rcv.h" +#include "extern.h" + +/* + * Allocate size more bytes of space and return the address of the + * first byte to the caller. An even number of bytes are always + * allocated so that the space will always be on a word boundary. + * The string spaces are of exponentially increasing size, to satisfy + * the occasional user with enormous string size requests. + */ + +char * +salloc(size) + int size; +{ + register char *t; + register int s; + register struct strings *sp; + int index; + + s = size; + s += 3; + s &= ~03; + index = 0; + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) { + if (sp->s_topFree == NOSTR && (STRINGSIZE << index) >= s) + break; + if (sp->s_nleft >= s) + break; + index++; + } + if (sp >= &stringdope[NSPACE]) + panic("String too large"); + if (sp->s_topFree == NOSTR) { + index = sp - &stringdope[0]; + sp->s_topFree = malloc(STRINGSIZE << index); + if (sp->s_topFree == NOSTR) { + fprintf(stderr, "No room for space %d\n", index); + panic("Internal error"); + } + sp->s_nextFree = sp->s_topFree; + sp->s_nleft = STRINGSIZE << index; + } + sp->s_nleft -= s; + t = sp->s_nextFree; + sp->s_nextFree += s; + return(t); +} + +/* + * Reset the string area to be empty. + * Called to free all strings allocated + * since last reset. + */ +void +sreset() +{ + register struct strings *sp; + register int index; + + if (noreset) + return; + index = 0; + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) { + if (sp->s_topFree == NOSTR) + continue; + sp->s_nextFree = sp->s_topFree; + sp->s_nleft = STRINGSIZE << index; + index++; + } +} + +/* + * Make the string area permanent. + * Meant to be called in main, after initialization. + */ +void +spreserve() +{ + register struct strings *sp; + + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) + sp->s_topFree = NOSTR; +} diff --git a/usr.bin/mail/temp.c b/usr.bin/mail/temp.c new file mode 100644 index 0000000..9162c9f --- /dev/null +++ b/usr.bin/mail/temp.c @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)temp.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * Give names to all the temporary files that we will need. + */ + +char tempMail[24]; +char tempQuit[24]; +char tempEdit[24]; +char tempResid[24]; +char tempMesg[24]; +char *tmpdir; + +void +tinit() +{ + register char *cp; + int len; + + if ((tmpdir = getenv("TMPDIR")) == NULL) + tmpdir = _PATH_TMP; + else { + len = strlen(tmpdir); + if ((cp = malloc(len + 2)) == NULL) { + (void)fprintf(stderr, "mail: %s\n", strerror(errno)); + exit (1); + } + (void)strcpy(cp, tmpdir); + cp[len] = '/'; + cp[len + 1] = '\0'; + tmpdir = cp; + } + + strcpy(tempMail, tmpdir); + mktemp(strcat(tempMail, "RsXXXXXX")); + strcpy(tempResid, tmpdir); + mktemp(strcat(tempResid, "RqXXXXXX")); + strcpy(tempQuit, tmpdir); + mktemp(strcat(tempQuit, "RmXXXXXX")); + strcpy(tempEdit, tmpdir); + mktemp(strcat(tempEdit, "ReXXXXXX")); + strcpy(tempMesg, tmpdir); + mktemp(strcat(tempMesg, "RxXXXXXX")); + + /* + * It's okay to call savestr in here because main will + * do a spreserve() after us. + */ + if (myname != NOSTR) { + if (getuserid(myname) < 0) { + printf("\"%s\" is not a user of this system\n", + myname); + exit(1); + } + } else { + if ((cp = username()) == NOSTR) { + myname = "ubluit"; + if (rcvmode) { + printf("Who are you!?\n"); + exit(1); + } + } else + myname = savestr(cp); + } + if ((cp = getenv("HOME")) == NOSTR) + cp = "."; + homedir = savestr(cp); + if (debug) + printf("user = %s, homedir = %s\n", myname, homedir); +} diff --git a/usr.bin/mail/tty.c b/usr.bin/mail/tty.c new file mode 100644 index 0000000..b39eba5 --- /dev/null +++ b/usr.bin/mail/tty.c @@ -0,0 +1,273 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Generally useful tty stuff. + */ + +#include "rcv.h" +#include "extern.h" + +static int c_erase; /* Current erase char */ +static int c_kill; /* Current kill char */ +static jmp_buf rewrite; /* Place to go when continued */ +static jmp_buf intjmp; /* Place to go when interrupted */ +#ifndef TIOCSTI +static int ttyset; /* We must now do erase/kill */ +#endif + +/* + * Read all relevant header fields. + */ + +int +grabh(hp, gflags) + struct header *hp; + int gflags; +{ + struct sgttyb ttybuf; + sig_t saveint; +#ifndef TIOCSTI + sig_t savequit; +#endif + sig_t savetstp; + sig_t savettou; + sig_t savettin; + int errs; + void ttyint(); + + savetstp = signal(SIGTSTP, SIG_DFL); + savettou = signal(SIGTTOU, SIG_DFL); + savettin = signal(SIGTTIN, SIG_DFL); + errs = 0; +#ifndef TIOCSTI + ttyset = 0; +#endif + if (ioctl(fileno(stdin), TIOCGETP, &ttybuf) < 0) { + perror("gtty"); + return(-1); + } + c_erase = ttybuf.sg_erase; + c_kill = ttybuf.sg_kill; +#ifndef TIOCSTI + ttybuf.sg_erase = 0; + ttybuf.sg_kill = 0; + if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) + signal(SIGINT, SIG_DFL); + if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) + signal(SIGQUIT, SIG_DFL); +#else + if (setjmp(intjmp)) + goto out; + saveint = signal(SIGINT, ttyint); +#endif + if (gflags & GTO) { +#ifndef TIOCSTI + if (!ttyset && hp->h_to != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_to = + extract(readtty("To: ", detract(hp->h_to, 0)), GTO); + } + if (gflags & GSUBJECT) { +#ifndef TIOCSTI + if (!ttyset && hp->h_subject != NOSTR) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_subject = readtty("Subject: ", hp->h_subject); + } + if (gflags & GCC) { +#ifndef TIOCSTI + if (!ttyset && hp->h_cc != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_cc = + extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); + } + if (gflags & GBCC) { +#ifndef TIOCSTI + if (!ttyset && hp->h_bcc != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_bcc = + extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); + } +out: + signal(SIGTSTP, savetstp); + signal(SIGTTOU, savettou); + signal(SIGTTIN, savettin); +#ifndef TIOCSTI + ttybuf.sg_erase = c_erase; + ttybuf.sg_kill = c_kill; + if (ttyset) + stty(fileno(stdin), &ttybuf); + signal(SIGQUIT, savequit); +#endif + signal(SIGINT, saveint); + return(errs); +} + +/* + * Read up a header from standard input. + * The source string has the preliminary contents to + * be read. + * + */ + +char * +readtty(pr, src) + char pr[], src[]; +{ + char ch, canonb[BUFSIZ]; + int c; + register char *cp, *cp2; + void ttystop(); + + fputs(pr, stdout); + fflush(stdout); + if (src != NOSTR && strlen(src) > BUFSIZ - 2) { + printf("too long to edit\n"); + return(src); + } +#ifndef TIOCSTI + if (src != NOSTR) + cp = copy(src, canonb); + else + cp = copy("", canonb); + fputs(canonb, stdout); + fflush(stdout); +#else + cp = src == NOSTR ? "" : src; + while (c = *cp++) { + if (c == c_erase || c == c_kill) { + ch = '\\'; + ioctl(0, TIOCSTI, &ch); + } + ch = c; + ioctl(0, TIOCSTI, &ch); + } + cp = canonb; + *cp = 0; +#endif + cp2 = cp; + while (cp2 < canonb + BUFSIZ) + *cp2++ = 0; + cp2 = cp; + if (setjmp(rewrite)) + goto redo; + signal(SIGTSTP, ttystop); + signal(SIGTTOU, ttystop); + signal(SIGTTIN, ttystop); + clearerr(stdin); + while (cp2 < canonb + BUFSIZ) { + c = getc(stdin); + if (c == EOF || c == '\n') + break; + *cp2++ = c; + } + *cp2 = 0; + signal(SIGTSTP, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + if (c == EOF && ferror(stdin)) { +redo: + cp = strlen(canonb) > 0 ? canonb : NOSTR; + clearerr(stdin); + return(readtty(pr, cp)); + } +#ifndef TIOCSTI + if (cp == NOSTR || *cp == '\0') + return(src); + cp2 = cp; + if (!ttyset) + return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR); + while (*cp != '\0') { + c = *cp++; + if (c == c_erase) { + if (cp2 == canonb) + continue; + if (cp2[-1] == '\\') { + cp2[-1] = c; + continue; + } + cp2--; + continue; + } + if (c == c_kill) { + if (cp2 == canonb) + continue; + if (cp2[-1] == '\\') { + cp2[-1] = c; + continue; + } + cp2 = canonb; + continue; + } + *cp2++ = c; + } + *cp2 = '\0'; +#endif + if (equal("", canonb)) + return(NOSTR); + return(savestr(canonb)); +} + +/* + * Receipt continuation. + */ +void +ttystop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + longjmp(rewrite, 1); +} + +/*ARGSUSED*/ +void +ttyint(s) + int s; +{ + longjmp(intjmp, 1); +} diff --git a/usr.bin/mail/v7.local.c b/usr.bin/mail/v7.local.c new file mode 100644 index 0000000..5144c01 --- /dev/null +++ b/usr.bin/mail/v7.local.c @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)v7.local.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Version 7 + * + * Local routines that are installation dependent. + */ + +#include "rcv.h" +#include +#include "extern.h" + +/* + * Locate the user's mailbox file (ie, the place where new, unread + * mail is queued). + */ +void +findmail(user, buf) + char *user, *buf; +{ + (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, user); +} + +/* + * Get rid of the queued mail. + */ +void +demail() +{ + + if (value("keep") != NOSTR || rm(mailname) < 0) + close(creat(mailname, 0600)); +} + +/* + * Discover user login name. + */ +char * +username() +{ + char *np; + + if ((np = getenv("USER")) != NOSTR) + return np; + return getname(getuid()); +} diff --git a/usr.bin/mail/vars.c b/usr.bin/mail/vars.c new file mode 100644 index 0000000..2a90442 --- /dev/null +++ b/usr.bin/mail/vars.c @@ -0,0 +1,190 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Variable handling stuff. + */ + +/* + * Assign a value to a variable. + */ +void +assign(name, value) + char name[], value[]; +{ + register struct var *vp; + register int h; + + h = hash(name); + vp = lookup(name); + if (vp == NOVAR) { + vp = (struct var *) calloc(sizeof *vp, 1); + vp->v_name = vcopy(name); + vp->v_link = variables[h]; + variables[h] = vp; + } + else + vfree(vp->v_value); + vp->v_value = vcopy(value); +} + +/* + * Free up a variable string. We do not bother to allocate + * strings whose value is "" since they are expected to be frequent. + * Thus, we cannot free same! + */ +void +vfree(cp) + char *cp; +{ + if (*cp) + free(cp); +} + +/* + * Copy a variable value into permanent (ie, not collected after each + * command) space. Do not bother to alloc space for "" + */ + +char * +vcopy(str) + char str[]; +{ + char *new; + unsigned len; + + if (*str == '\0') + return ""; + len = strlen(str) + 1; + if ((new = malloc(len)) == NULL) + panic("Out of memory"); + bcopy(str, new, (int) len); + return new; +} + +/* + * Get the value of a variable and return it. + * Look in the environment if its not available locally. + */ + +char * +value(name) + char name[]; +{ + register struct var *vp; + + if ((vp = lookup(name)) == NOVAR) + return(getenv(name)); + return(vp->v_value); +} + +/* + * Locate a variable and return its variable + * node. + */ + +struct var * +lookup(name) + register char name[]; +{ + register struct var *vp; + + for (vp = variables[hash(name)]; vp != NOVAR; vp = vp->v_link) + if (*vp->v_name == *name && equal(vp->v_name, name)) + return(vp); + return(NOVAR); +} + +/* + * Locate a group name and return it. + */ + +struct grouphead * +findgroup(name) + register char name[]; +{ + register struct grouphead *gh; + + for (gh = groups[hash(name)]; gh != NOGRP; gh = gh->g_link) + if (*gh->g_name == *name && equal(gh->g_name, name)) + return(gh); + return(NOGRP); +} + +/* + * Print a group out on stdout + */ +void +printgroup(name) + char name[]; +{ + register struct grouphead *gh; + register struct group *gp; + + if ((gh = findgroup(name)) == NOGRP) { + printf("\"%s\": not a group\n", name); + return; + } + printf("%s\t", gh->g_name); + for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) + printf(" %s", gp->ge_name); + putchar('\n'); +} + +/* + * Hash the passed string and return an index into + * the variable or group hash table. + */ +int +hash(name) + register char *name; +{ + register h = 0; + + while (*name) { + h <<= 2; + h += *name++; + } + if (h < 0 && (h = -h) < 0) + h = 0; + return (h % HSHSIZE); +} diff --git a/usr.bin/mail/version.c b/usr.bin/mail/version.c new file mode 100644 index 0000000..c7d39c3 --- /dev/null +++ b/usr.bin/mail/version.c @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)version.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Just keep track of the date/sid of this version of Mail. + * Load this file first to get a "total" Mail version. + */ +char *version = "8.1 6/6/93"; diff --git a/usr.bin/make/Makefile.dist b/usr.bin/make/Makefile.dist new file mode 100644 index 0000000..c311d7e --- /dev/null +++ b/usr.bin/make/Makefile.dist @@ -0,0 +1,7 @@ +# a very simple makefile... +pmake: + @echo 'make started.' + cc -I. -c *.c + cd lst.lib; cc -I.. -c *.c + cc *.o lst.lib/*.o -o pmake + @echo 'make completed.' diff --git a/usr.bin/make/bit.h b/usr.bin/make/bit.h new file mode 100644 index 0000000..85117a4 --- /dev/null +++ b/usr.bin/make/bit.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1988, 1989, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bit.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * bit.h -- + * + * Definition of macros for setting and clearing bits in an array + * of integers. + * + * It is assumed that "int" is 32 bits wide. + */ + +#ifndef _BIT +#define _BIT + +#include "sprite.h" + +#define BIT_NUM_BITS_PER_INT 32 +#define BIT_NUM_BITS_PER_BYTE 8 + +#define Bit_NumInts(numBits) \ + (((numBits)+BIT_NUM_BITS_PER_INT -1)/BIT_NUM_BITS_PER_INT) + +#define Bit_NumBytes(numBits) \ + (Bit_NumInts(numBits) * sizeof(int)) + +#define Bit_Alloc(numBits, bitArrayPtr) \ + bitArrayPtr = (int *)malloc((unsigned)Bit_NumBytes(numBits)); \ + Bit_Zero((numBits), (bitArrayPtr)) + +#define Bit_Free(bitArrayPtr) \ + free((char *)bitArrayPtr) + +#define Bit_Set(numBits, bitArrayPtr) \ + ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] |= \ + (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) + +#define Bit_IsSet(numBits, bitArrayPtr) \ + ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] & \ + (1 << ((numBits) % BIT_NUM_BITS_PER_INT))) + +#define Bit_Clear(numBits, bitArrayPtr) \ + ((bitArrayPtr)[(numBits)/BIT_NUM_BITS_PER_INT] &= \ + ~(1 << ((numBits) % BIT_NUM_BITS_PER_INT))) + +#define Bit_IsClear(numBits, bitArrayPtr) \ + (!(Bit_IsSet((numBits), (bitArrayPtr)))) + +#define Bit_Copy(numBits, srcArrayPtr, destArrayPtr) \ + bcopy((char *)(srcArrayPtr), (char *)(destArrayPtr), \ + Bit_NumBytes(numBits)) + +#define Bit_Zero(numBits, bitArrayPtr) \ + bzero((char *)(bitArrayPtr), Bit_NumBytes(numBits)) + +extern int Bit_FindFirstSet(); +extern int Bit_FindFirstClear(); +extern Boolean Bit_Intersect(); +extern Boolean Bit_Union(); +extern Boolean Bit_AnySet(); +extern int *Bit_Expand(); + +#endif /* _BIT */ diff --git a/usr.bin/man/Makefile b/usr.bin/man/Makefile new file mode 100644 index 0000000..728d038 --- /dev/null +++ b/usr.bin/man/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= man +SRCS= config.c man.c +MAN1= man.0 +MAN5= man.conf.0 + +.include diff --git a/usr.bin/man/config.c b/usr.bin/man/config.c new file mode 100644 index 0000000..1d875b5 --- /dev/null +++ b/usr.bin/man/config.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)config.c 8.7 (Berkeley) 1/3/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "pathnames.h" + +struct _head head; + +/* + * config -- + * + * Read the configuration file and build a doubly linked + * list that looks like: + * + * tag1 <-> record <-> record <-> record + * | + * tag2 <-> record <-> record <-> record + */ +void +config(fname) + char *fname; +{ + TAG *tp; + ENTRY *ep; + FILE *cfp; + size_t len; + int lcnt; + char *p, *t; + + if (fname == NULL) + fname = _PATH_MANCONF; + if ((cfp = fopen(fname, "r")) == NULL) + err(1, "%s", fname); + TAILQ_INIT(&head); + for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) { + if (len == 1) /* Skip empty lines. */ + continue; + if (p[len - 1] != '\n') { /* Skip corrupted lines. */ + warnx("%s: line %d corrupted", fname, lcnt); + continue; + } + p[len - 1] = '\0'; /* Terminate the line. */ + + /* Skip leading space. */ + for (; *p != '\0' && isspace(*p); ++p); + /* Skip empty/comment lines. */ + if (*p == '\0' || *p == '#') + continue; + /* Find first token. */ + for (t = p; *t && !isspace(*t); ++t); + if (*t == '\0') /* Need more than one token.*/ + continue; + *t = '\0'; + + for (tp = head.tqh_first; /* Find any matching tag. */ + tp != NULL && strcmp(p, tp->s); tp = tp->q.tqe_next); + + if (tp == NULL) /* Create a new tag. */ + tp = addlist(p); + + /* + * Attach new records. The keyword _build takes the rest of + * the line as a single entity, everything else is white + * space separated. The reason we're not just using strtok(3) + * for all of the parsing is so we don't get caught if a line + * has only a single token on it. + */ + if (!strcmp(p, "_build")) { + while (*++t && isspace(*t)); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(t)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(&tp->list, ep, q); + } else for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) { + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(p)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(&tp->list, ep, q); + } + } +} + +/* + * addlist -- + * Add a tag to the list. + */ +TAG * +addlist(name) + char *name; +{ + TAG *tp; + + if ((tp = calloc(1, sizeof(TAG))) == NULL || + (tp->s = strdup(name)) == NULL) + err(1, NULL); + TAILQ_INIT(&tp->list); + TAILQ_INSERT_TAIL(&head, tp, q); + return (tp); +} + +/* + * getlist -- + * Return the linked list of entries for a tag if it exists. + */ +TAG * +getlist(name) + char *name; +{ + TAG *tp; + + for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next) + if (!strcmp(name, tp->s)) + return (tp); + return (NULL); +} + +void +debug(l) + char *l; +{ + TAG *tp; + ENTRY *ep; + + (void)printf("%s ===============\n", l); + for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next) { + printf("%s\n", tp->s); + for (ep = tp->list.tqh_first; ep != NULL; ep = ep->q.tqe_next) + printf("\t%s\n", ep->s); + } +} diff --git a/usr.bin/man/config.h b/usr.bin/man/config.h new file mode 100644 index 0000000..52ea969 --- /dev/null +++ b/usr.bin/man/config.h @@ -0,0 +1,57 @@ +/*- + * 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. + * + * @(#)config.h 8.4 (Berkeley) 12/18/93 + */ + +typedef struct _tag { + TAILQ_ENTRY(_tag) q; /* Queue of tags. */ + + TAILQ_HEAD(tqh, _entry) list; /* Queue of entries. */ + char *s; /* Associated string. */ + size_t len; /* Length of 's'. */ +} TAG; +typedef struct _entry { + TAILQ_ENTRY(_entry) q; /* Queue of entries. */ + + char *s; /* Associated string. */ + size_t len; /* Length of 's'. */ +} ENTRY; + +TAILQ_HEAD(_head, _tag); +extern struct _head head; + +TAG *addlist __P((char *)); +void config __P((char *)); +void debug __P((char *)); +TAG *getlist __P((char *)); diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 new file mode 100644 index 0000000..081e204 --- /dev/null +++ b/usr.bin/man/man.1 @@ -0,0 +1,188 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)man.1 8.2 (Berkeley) 1/2/94 +.\" +.Dd January 2, 1994 +.Dt MAN 1 +.Os BSD 4 +.Sh NAME +.Nm man +.Nd display the on-line manual pages +.Sh SYNOPSIS +.Nm man +.Op Fl achw +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Op Ar section +.Ar name Ar ... +.Sh DESCRIPTION +The +.Nm man +utility +displays the +.Bx +manual pages entitled +.Ar name . +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a +Display all of the manual pages for a specified +.Ar section +and +.Ar name +combination. +(Normally, only the first manual page found is displayed.) +.It Fl C +Use the specified +.Ar file +instead of the default configuration file. +This permits users to configure their own manual environment. +See +.Xr man.conf 5 +for a description of the contents of this file. +.It Fl c +Copy the manual page to the standard output instead of using +.Xr more 1 +to paginate it. +This is done by default if the standard output is not a terminal device. +.It Fl h +Display only the +.Dq Tn SYNOPSIS +lines of the requested manual pages. +.It Fl M +Override the list of standard directories which +.Nm man +searches for manual pages. +The supplied +.Ar path +must be a colon (``:'') separated list of directories. +This search path may also be set using the environment variable +.Ev MANPATH . +The subdirectories to be searched, and their search order, +is specified by the ``_subdir'' line in the +.Nm man +configuration file. +.It Fl m +Augment the list of standard directories which +.Nm man +searches for manual pages. +The supplied +.Ar path +must be a colon (``:'') separated list of directories. +These directories will be searched before the standard directories or +the directories specified using the +.Fl M +option or the +.Ev MANPATH +environment variable. +The subdirectories to be searched, and their search order, +is specified by the ``_subdir'' line in the +.Nm man +configuration file. +.It Fl w +List the pathnames of the manual pages which +.Nm man +would display for the specified +.Ar section +and +.Ar name +combination. +.El +.Pp +The optional +.Ar section +argument restricts the directories that +.Nm man +will search. +The +.Nm man +configuration file (see +.Xr man.conf 5 ) +specifies the possible +.Ar section +values that are currently available. +If only a single argument is specified or if the first argument is +not a valid section, +.Nm man +assumes that the argument is the name of a manual page to be displayed. +.Sh ENVIRONMENT +.Bl -tag -width MANPATHX +.It Ev MACHINE +As some manual pages are intended only for specific architectures, +.Nm man +searches any subdirectories, +with the same name as the current architecture, +in every directory which it searches. +Machine specific areas are checked before general areas. +The current machine type may be overridden by setting the environment +variable +.Ev MACHINE +to the name of a specific architecture. +.It Ev MANPATH +The standard search path used by +.Nm man +may be overridden by specifying a path in the +.Ev MANPATH +environment +variable. +The format of the path is a colon (``:'') separated list of directories. +The subdirectories to be searched as well as their search order +is specified by the ``_subdir'' line in the +.Nm man +configuration file. +.It Ev PAGER +Any value of the environment variable +.Ev PAGER +will be used instead of the standard pagination program, +.Xr more 1 . +.El +.Sh FILES +.Bl -tag -width /etc/man.conf -compact +.It Pa /etc/man.conf +default man configuration file. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr whatis 1 , +.Xr whereis 1 , +.Xr man.conf 5 +.Sh BUGS +The on-line manual pages are, by necessity, forgiving toward stupid +display devices, causing a few manual pages to not as nicely formatted +as their typeset counterparts. +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/man/man.c b/usr.bin/man/man.c new file mode 100644 index 0000000..a320e31 --- /dev/null +++ b/usr.bin/man/man.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)man.c 8.16 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "pathnames.h" + +int f_all, f_where; + +static void build_page __P((char *, char **)); +static void cat __P((char *)); +static char *check_pager __P((char *)); +static int cleanup __P((void)); +static void how __P((char *)); +static void jump __P((char **, char *, char *)); +static int manual __P((char *, TAG *, glob_t *)); +static void onsig __P((int)); +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + TAG *defp, *defnewp, *section, *sectnewp, *subp; + ENTRY *e_defp, *e_sectp, *e_subp, *ep; + glob_t pg; + size_t len; + int ch, f_cat, f_how, found; + char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp; + char *conffile, buf[MAXPATHLEN * 2]; + + f_cat = f_how = 0; + conffile = p_add = p_path = NULL; + while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:w")) != EOF) + switch (ch) { + case 'a': + f_all = 1; + break; + case 'C': + conffile = optarg; + break; + case 'c': + case '-': /* Deprecated. */ + f_cat = 1; + break; + case 'h': + f_how = 1; + break; + case 'm': + p_add = optarg; + break; + case 'M': + case 'P': /* Backward compatibility. */ + p_path = optarg; + break; + /* + * The -f and -k options are backward compatible, + * undocumented ways of calling whatis(1) and apropos(1). + */ + case 'f': + jump(argv, "-f", "whatis"); + /* NOTREACHED */ + case 'k': + jump(argv, "-k", "apropos"); + /* NOTREACHED */ + case 'w': + f_all = f_where = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!*argv) + usage(); + + if (!f_cat && !f_how && !f_where) + if (!isatty(1)) + f_cat = 1; + else if ((pager = getenv("PAGER")) != NULL) + pager = check_pager(pager); + else + pager = _PATH_PAGER; + + /* Read the configuration file. */ + config(conffile); + + /* Get the machine type. */ + if ((machine = getenv("MACHINE")) == NULL) + machine = MACHINE; + + /* If there's no _default list, create an empty one. */ + if ((defp = getlist("_default")) == NULL) + defp = addlist("_default"); + + /* + * 1: If the user specified a MANPATH variable, or set the -M + * option, we replace the _default list with the user's list, + * appending the entries in the _subdir list and the machine. + */ + if (p_path == NULL) + p_path = getenv("MANPATH"); + if (p_path != NULL) { + while ((e_defp = defp->list.tqh_first) != NULL) { + free(e_defp->s); + TAILQ_REMOVE(&defp->list, e_defp, q); + } + for (p = strtok(p_path, ":"); + p != NULL; p = strtok(NULL, ":")) { + slashp = p[strlen(p) - 1] == '/' ? "" : "/"; + e_subp = (subp = getlist("_subdir")) == NULL ? + NULL : subp->list.tqh_first; + for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + p, slashp, e_subp->s, machine); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(buf)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(&defp->list, ep, q); + } + } + } + + /* + * 2: If the user did not specify MANPATH, -M or a section, rewrite + * the _default list to include the _subdir list and the machine. + */ + if (argv[1] == NULL) + section = NULL; + else if ((section = getlist(*argv)) != NULL) + ++argv; + if (p_path == NULL && section == NULL) { + defnewp = addlist("_default_new"); + e_defp = + defp->list.tqh_first == NULL ? NULL : defp->list.tqh_first; + for (; e_defp != NULL; e_defp = e_defp->q.tqe_next) { + slashp = + e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/"; + e_subp = (subp = getlist("_subdir")) == NULL ? + NULL : subp->list.tqh_first; + for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + e_defp->s, slashp, e_subp->s, machine); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(buf)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(&defnewp->list, ep, q); + } + } + defp = getlist("_default"); + while ((e_defp = defp->list.tqh_first) != NULL) { + free(e_defp->s); + TAILQ_REMOVE(&defp->list, e_defp, q); + } + free(defp->s); + TAILQ_REMOVE(&head, defp, q); + defnewp = getlist("_default_new"); + free(defnewp->s); + defnewp->s = "_default"; + defp = defnewp; + } + + /* + * 3: If the user set the -m option, insert the user's list before + * whatever list we have, again appending the _subdir list and + * the machine. + */ + if (p_add != NULL) + for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) { + slashp = p[strlen(p) - 1] == '/' ? "" : "/"; + e_subp = (subp = getlist("_subdir")) == NULL ? + NULL : subp->list.tqh_first; + for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + p, slashp, e_subp->s, machine); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(buf)) == NULL) + err(1, NULL); + TAILQ_INSERT_HEAD(&defp->list, ep, q); + } + } + + /* + * 4: If none of MANPATH, -M, or -m were specified, and a section was, + * rewrite the section's paths (if they have a trailing slash) to + * append the _subdir list and the machine. This then becomes the + * _default list. + */ + if (p_path == NULL && p_add == NULL && section != NULL) { + sectnewp = addlist("_section_new"); + for (e_sectp = section->list.tqh_first; + e_sectp != NULL; e_sectp = e_sectp->q.tqe_next) { + if (e_sectp->s[strlen(e_sectp->s) - 1] != '/') { + (void)snprintf(buf, sizeof(buf), + "%s{/%s,}", e_sectp->s, machine); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(buf)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(§newp->list, ep, q); + continue; + } + e_subp = (subp = getlist("_subdir")) == NULL ? + NULL : subp->list.tqh_first; + for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s%s{/%s,}", + e_sectp->s, e_subp->s, machine); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(buf)) == NULL) + err(1, NULL); + TAILQ_INSERT_TAIL(§newp->list, ep, q); + } + } + sectnewp->s = section->s; + defp = sectnewp; + TAILQ_REMOVE(&head, section, q); + } + + /* + * 5: Search for the files. Set up an interrupt handler, so the + * temporary files go away. + */ + (void)signal(SIGINT, onsig); + (void)signal(SIGHUP, onsig); + + memset(&pg, 0, sizeof(pg)); + for (found = 0; *argv; ++argv) + if (manual(*argv, defp, &pg)) + found = 1; + + /* 6: If nothing found, we're done. */ + if (!found) { + (void)cleanup(); + exit (1); + } + + /* 7: If it's simple, display it fast. */ + if (f_cat) { + for (ap = pg.gl_pathv; *ap != NULL; ++ap) { + if (**ap == '\0') + continue; + cat(*ap); + } + exit (cleanup()); + } + if (f_how) { + for (ap = pg.gl_pathv; *ap != NULL; ++ap) { + if (**ap == '\0') + continue; + how(*ap); + } + exit(cleanup()); + } + if (f_where) { + for (ap = pg.gl_pathv; *ap != NULL; ++ap) { + if (**ap == '\0') + continue; + (void)printf("%s\n", *ap); + } + exit(cleanup()); + } + + /* + * 8: We display things in a single command; build a list of things + * to display. + */ + for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) { + if (**ap == '\0') + continue; + len += strlen(*ap) + 1; + } + if ((cmd = malloc(len)) == NULL) { + warn(NULL); + (void)cleanup(); + exit(1); + } + p = cmd; + len = strlen(pager); + memmove(p, pager, len); + p += len; + *p++ = ' '; + for (ap = pg.gl_pathv; *ap != NULL; ++ap) { + if (**ap == '\0') + continue; + len = strlen(*ap); + memmove(p, *ap, len); + p += len; + *p++ = ' '; + } + *p = '\0'; + + /* Use system(3) in case someone's pager is "pager arg1 arg2". */ + (void)system(cmd); + + exit(cleanup()); +} + +/* + * manual -- + * Search the manuals for the pages. + */ +static int +manual(page, tag, pg) + char *page; + TAG *tag; + glob_t *pg; +{ + ENTRY *ep, *e_sufp, *e_tag; + TAG *missp, *sufp; + int anyfound, cnt, found; + char *p, buf[128]; + + anyfound = 0; + buf[0] = '*'; + + /* For each element in the list... */ + e_tag = tag == NULL ? NULL : tag->list.tqh_first; + for (; e_tag != NULL; e_tag = e_tag->q.tqe_next) { + (void)snprintf(buf, sizeof(buf), "%s/%s.*", e_tag->s, page); + if (glob(buf, + GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE, + NULL, pg)) { + warn("globbing"); + (void)cleanup(); + exit(1); + } + if (pg->gl_matchc == 0) + continue; + + /* Find out if it's really a man page. */ + for (cnt = pg->gl_pathc - pg->gl_matchc; + cnt < pg->gl_pathc; ++cnt) { + + /* + * Try the _suffix key words first. + * + * XXX + * Older versions of man.conf didn't have the suffix + * key words, it was assumed that everything was a .0. + * We just test for .0 first, it's fast and probably + * going to hit. + */ + (void)snprintf(buf, sizeof(buf), "*/%s.0", page); + if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) + goto next; + + e_sufp = (sufp = getlist("_suffix")) == NULL ? + NULL : sufp->list.tqh_first; + for (found = 0; + e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) { + (void)snprintf(buf, + sizeof(buf), "*/%s%s", page, e_sufp->s); + if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { + found = 1; + break; + } + } + if (found) + goto next; + + /* Try the _build key words next. */ + e_sufp = (sufp = getlist("_build")) == NULL ? + NULL : sufp->list.tqh_first; + for (found = 0; + e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) { + for (p = e_sufp->s; + *p != '\0' && !isspace(*p); ++p); + if (*p == '\0') + continue; + *p = '\0'; + (void)snprintf(buf, + sizeof(buf), "*/%s%s", page, e_sufp->s); + if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { + if (!f_where) + build_page(p + 1, + &pg->gl_pathv[cnt]); + *p = ' '; + found = 1; + break; + } + *p = ' '; + } + if (found) { +next: anyfound = 1; + if (!f_all) { + /* Delete any other matches. */ + while (++cnt< pg->gl_pathc) + pg->gl_pathv[cnt] = ""; + break; + } + continue; + } + + /* It's not a man page, forget about it. */ + pg->gl_pathv[cnt] = ""; + } + + if (anyfound && !f_all) + break; + } + + /* If not found, enter onto the missing list. */ + if (!anyfound) { + if ((missp = getlist("_missing")) == NULL) + missp = addlist("_missing"); + if ((ep = malloc(sizeof(ENTRY))) == NULL || + (ep->s = strdup(page)) == NULL) { + warn(NULL); + (void)cleanup(); + exit(1); + } + TAILQ_INSERT_TAIL(&missp->list, ep, q); + } + return (anyfound); +} + +/* + * build_page -- + * Build a man page for display. + */ +static void +build_page(fmt, pathp) + char *fmt, **pathp; +{ + static int warned; + ENTRY *ep; + TAG *intmpp; + int fd; + char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)]; + + /* Let the user know this may take awhile. */ + if (!warned) { + warned = 1; + warnx("Formatting manual page..."); + } + + /* Add a remove-when-done list. */ + if ((intmpp = getlist("_intmp")) == NULL) + intmpp = addlist("_intmp"); + + /* Move to the printf(3) format string. */ + for (; *fmt && isspace(*fmt); ++fmt); + + /* + * Get a temporary file and build a version of the file + * to display. Replace the old file name with the new one. + */ + (void)strcpy(tpath, _PATH_TMP); + if ((fd = mkstemp(tpath)) == -1) { + warn("%s", tpath); + (void)cleanup(); + exit(1); + } + (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); + (void)snprintf(cmd, sizeof(cmd), buf, *pathp); + (void)system(cmd); + (void)close(fd); + if ((*pathp = strdup(tpath)) == NULL) { + warn(NULL); + (void)cleanup(); + exit(1); + } + + /* Link the built file into the remove-when-done list. */ + if ((ep = malloc(sizeof(ENTRY))) == NULL) { + warn(NULL); + (void)cleanup(); + exit(1); + } + ep->s = *pathp; + TAILQ_INSERT_TAIL(&intmpp->list, ep, q); +} + +/* + * how -- + * display how information + */ +static void +how(fname) + char *fname; +{ + FILE *fp; + + int lcnt, print; + char *p, buf[256]; + + if (!(fp = fopen(fname, "r"))) { + warn("%s", fname); + (void)cleanup(); + exit (1); + } +#define S1 "SYNOPSIS" +#define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" +#define D1 "DESCRIPTION" +#define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" + for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { + if (!strncmp(buf, S1, sizeof(S1) - 1) || + !strncmp(buf, S2, sizeof(S2) - 1)) { + print = 1; + continue; + } else if (!strncmp(buf, D1, sizeof(D1) - 1) || + !strncmp(buf, D2, sizeof(D2) - 1)) + return; + if (!print) + continue; + if (*buf == '\n') + ++lcnt; + else { + for(; lcnt; --lcnt) + (void)putchar('\n'); + for (p = buf; isspace(*p); ++p); + (void)fputs(p, stdout); + } + } + (void)fclose(fp); +} + +/* + * cat -- + * cat out the file + */ +static void +cat(fname) + char *fname; +{ + int fd, n; + char buf[2048]; + + if ((fd = open(fname, O_RDONLY, 0)) < 0) { + warn("%s", fname); + (void)cleanup(); + exit(1); + } + while ((n = read(fd, buf, sizeof(buf))) > 0) + if (write(STDOUT_FILENO, buf, n) != n) { + warn("write"); + (void)cleanup(); + exit (1); + } + if (n == -1) { + warn("read"); + (void)cleanup(); + exit(1); + } + (void)close(fd); +} + +/* + * check_pager -- + * check the user supplied page information + */ +static char * +check_pager(name) + char *name; +{ + char *p, *save; + + /* + * if the user uses "more", we make it "more -s"; watch out for + * PAGER = "mypager /usr/ucb/more" + */ + for (p = name; *p && !isspace(*p); ++p); + for (; p > name && *p != '/'; --p); + if (p != name) + ++p; + + /* make sure it's "more", not "morex" */ + if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ + save = name; + /* allocate space to add the "-s" */ + if (!(name = + malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) + err(1, NULL); + (void)sprintf(name, "%s %s", save, "-s"); + } + return(name); +} + +/* + * jump -- + * strip out flag argument and jump + */ +static void +jump(argv, flag, name) + char **argv, *flag, *name; +{ + char **arg; + + argv[0] = name; + for (arg = argv + 1; *arg; ++arg) + if (!strcmp(*arg, flag)) + break; + for (; *arg; ++arg) + arg[0] = arg[1]; + execvp(name, argv); + (void)fprintf(stderr, "%s: Command not found.\n", name); + exit(1); +} + +/* + * onsig -- + * If signaled, delete the temporary files. + */ +static void +onsig(signo) + int signo; +{ + (void)cleanup(); + + (void)signal(signo, SIG_DFL); + (void)kill(getpid(), signo); + + /* NOTREACHED */ + exit (1); +} + +/* + * cleanup -- + * Clean up temporary files, show any error messages. + */ +static int +cleanup() +{ + TAG *intmpp, *missp; + ENTRY *ep; + int rval; + + rval = 0; + ep = (missp = getlist("_missing")) == NULL ? + NULL : missp->list.tqh_first; + if (ep != NULL) + for (; ep != NULL; ep = ep->q.tqe_next) { + warnx("no entry for %s in the manual.", ep->s); + rval = 1; + } + + ep = (intmpp = getlist("_intmp")) == NULL ? + NULL : intmpp->list.tqh_first; + for (; ep != NULL; ep = ep->q.tqe_next) + (void)unlink(ep->s); + return (rval); +} + +/* + * usage -- + * print usage message and die + */ +static void +usage() +{ + (void)fprintf(stderr, + "usage: man [-achw] [-C file] [-M path] [-m path] [section] title ...\n"); + exit(1); +} diff --git a/usr.bin/man/man.conf b/usr.bin/man/man.conf new file mode 100644 index 0000000..9faad52 --- /dev/null +++ b/usr.bin/man/man.conf @@ -0,0 +1,46 @@ +# Sheer, raging paranoia... +_version BSD.2 + +# The whatis/apropos database. +_whatdb /usr/share/man/whatis.db + +# Subdirectories for paths ending in '/', IN SEARCH ORDER. +_subdir cat{1,8,6,2,3,4,5,7,3f} + +# Files typed by suffix and their commands. +# Note the order, .Z must come after .[1-9].Z, or it will match first. +_suffix .0 +_build .[1-9] /usr/bin/nroff -man %s +_build .[1-9].Z /usr/bin/zcat %s | /usr/bin/nroff -man +_build .Z /usr/bin/zcat %s +_build .0.Z /usr/bin/zcat %s +_build .gz /usr/contrib/bin/gunzip %s +_build .z /usr/contrib/bin/gunzip %s +_build .nr /usr/bin/nroff -man %s + +# Sections and their directories. +# All paths ending in '/' are the equivalent of entries specifying that +# directory with all of the subdirectories listed for the keyword _subdir. + +# default +_default /usr/{share,X11,contrib,local}/{man,man/old}/ + +# Other sections that represent complete man subdirectories. +X11 /usr/X11R4/man/ +X11R4 /usr/X11R4/man/ +contrib /usr/contrib/man/ +local /usr/local/man/ +new /usr/contrib/man/ +old /usr/share/man/old/ + +# Specific section/directory combinations. +1 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat1 +2 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat2 +3 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat3 +3F /usr/share/man/cat3f +3f /usr/share/man/cat3f +4 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat4 +5 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat5 +6 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat6 +7 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat7 +8 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat8 diff --git a/usr.bin/man/man.conf.5 b/usr.bin/man/man.conf.5 new file mode 100644 index 0000000..353a302 --- /dev/null +++ b/usr.bin/man/man.conf.5 @@ -0,0 +1,195 @@ +.\" Copyright (c) 1989, 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. +.\" +.\" @(#)man.conf.5 8.5 (Berkeley) 1/2/94 +.\" +.Dd January 2, 1994 +.Dt MAN.CONF 5 +.Os +.Sh NAME +.Nm man.conf +.Nd configuration file for +.Xr man 1 +.Sh DESCRIPTION +The +.Xr man 1 , +.Xr apropos 1 , +and +.Xr whatis 1 +commands +search for manual pages or their database files as specified by the +.Nm man.conf +file. +Manual pages are normally expected to be preformatted (see +.Xr nroff 1 ) +and named with a trailing ``.0''. +.Pp +The +.Nm man.conf +file contains two types of lines. +.Pp +The first type of line is a ``section'' line, which contains a +section name followed by one or more directory paths. +The directory paths may contain the normal shell globbing characters, +including curly braces (``{}''); to escape a shell globbing character, +precede it with a backslash (``\e''). +Lines in this format specify that manual pages for the section +may be found in the following directories. +.Pp +Directories named with a trailing slash character (``/'') are expected +to contain subdirectories of manual pages, (see the keyword ``_subdir'' +below) instead of manual pages. +These subdirectories are searched instead of the directory. +.Pp +Before searching any directory for a manual page, the +.Xr man 1 +command always searches the subdirectory with the same name +as the current machine type, if it exists. +No specification of these subdirectories is necessary in the +.Nm man.conf +file. +.Pp +Section names are unrestricted except for the reserved words specified +below; in general, you should avoid anything with a leading underscore +(``_'') to avoid future incompatibilities. +.Pp +The section named ``_default'' is the list of directories that will +be searched if no section is specified by the user. +.Pp +The second type of line is preceded with a ``keyword''. +The possible keywords and their meanings are as follows: +.Pp +.Bl -tag -width "_version" +.It _build +Man file names, regardless of their format, are expected to end in +a ``.*'' pattern, i.e. a ``.'' followed by some suffix. +The first field of a _build line lists a suffix which indicates +files which need to be reformated or manipulated in some way before +being displayed to the user. +The suffix may contain the normal shell globbing characters (NOT +including curly braces (``{}'')). +The rest of the line must be a shell command line, the standard +output of which is the manual page in a format which may be directly +displayed to the user. +Any occurrences of the string ``%s'' in the shell command line will +be replaced by the name of the file which is being reformatted. +.It _subdir +The list (in search order) of subdirectories which will be searched in +any directory named with a trailing slash (``/'') character. +This list is also used when a path is specified to the +.Xr man 1 +utility by the user, using the +.Ev MANPATH +environment variable or the +.Fl M +and +.Fl m +options. +.It _suffix +Man file names, regardless of their format are expected to end in +a ``.*'' pattern, i.e. a ``.'' followed by some suffix. +Each field of a _suffix line is a suffix which indicates +files which do not need to be reformatted or manipulated +in any way, but which may be directly displayed to the user. +Each suffix may contain the normal shell globbing characters (NOT +including curly braces (``{}'')). +.It _version +The version of the configuration file. +.It _whatdb +The full pathname (not just a directory path) for a database to be used +by the +.Xr apropos 1 +and +.Xr whatis 1 +commands. +.El +.Pp +Multiple specifications for all types of lines are cumulative and the +entries are used in the order listed in the file; multiple entries may +be listed per line, as well. +.Pp +Empty lines or lines whose first non-whitespace character is a hash +mark (``#'') are ignored. +.Sh EXAMPLES +Given the following +.Nm man.conf +file: +.Bd -literal -offset indent +_version BSD.2 +_subdir cat[123] +_suffix .0 +_build .[1-9] nroff -man %s +_build .tbl tbl %s | nroff -man +_default /usr/share/man/ +sect3 /usr/share/man/{old/,}cat3 +.Ed +.Pp +By default, the command +.Dq Li man mktemp +will search for +``mktemp.'' and ``mktemp.tbl'' +in the directories +.Dq Pa /usr/share/man/cat1 , +.Dq Pa /usr/share/man/cat2 , +and +.Dq Pa /usr/share/man/cat3 . +If on a machine of type ``vax'', the subdirectory ``vax'' in each +directory would be searched as well, before the directory was +searched. +.Pp +If ``mktemp.tbl'' was found first, the command +.Dq Li tbl | nroff -man +would be run to build a man page for display to the user. +.Pp +The command +.Dq Li man sect3 mktemp +would search the directories +.Dq Pa /usr/share/man/old/cat3 +and +.Dq Pa /usr/share/man/cat3 , +in that order, for +the mktemp manual page. +If a subdirectory with the same name as the current machine type +existed in any of them, it would be searched as well, before each +of them were searched. +.Sh FILES +.Bl -tag -width /etc/man.conf -compact +.It Pa /etc/man.conf +Standard manual directory search path. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr machine 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr whereis 1 , +.Xr fnmatch 3 , +.Xr glob 3 diff --git a/usr.bin/man/pathnames.h b/usr.bin/man/pathnames.h new file mode 100644 index 0000000..17284fe --- /dev/null +++ b/usr.bin/man/pathnames.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.3 (Berkeley) 1/2/94 + */ + +#define _PATH_MANCONF "/etc/man.conf" +#define _PATH_PAGER "/usr/bin/more -s" +#define _PATH_TMP "/tmp/man.XXXXXX" +#define _PATH_WHATIS "whatis.db" diff --git a/usr.bin/mesg/Makefile b/usr.bin/mesg/Makefile new file mode 100644 index 0000000..8c54356 --- /dev/null +++ b/usr.bin/mesg/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mesg + +.include diff --git a/usr.bin/mesg/mesg.1 b/usr.bin/mesg/mesg.1 new file mode 100644 index 0000000..70e29a9 --- /dev/null +++ b/usr.bin/mesg/mesg.1 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1987, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mesg.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MESG 1 +.Os +.Sh NAME +.Nm mesg +.Nd display (do not display) messages from other users +.Sh SYNOPSIS +.Nm mesg +.Op Cm n | Cm y +.Sh DESCRIPTION +The +.Nm mesg +utility is invoked by a users to control write access others +have to the terminal device associated with the standard error +output. +Write access is allowed by default, and programs such as +.Xr talk 1 +and +.Xr write 1 +may display messages on the terminal. +.Pp +Options available: +.Bl -tag -width flag +.It Cm n +Disallows messages. +.It Cm y +Permits messages to be displayed. +.El +.Pp +If no arguments are given, +.Nm mesg +displays the present message status to the standard error output. +.Pp +The +.Nm mesg +utility exits with one of the following values: +.Bl -tag -width flag -compact -offset indent +.Pp +.It Li "\ 0" +Messages are allowed. +.It Li "\ 1" +Messages are not allowed. +.It Li "\>1" +An error has occurred. +.El +.Sh FILES +.Bl -tag -width /dev/[pt]ty[pq]? -compact +.It Pa /dev/[pt]ty[pq]? +.El +.Sh SEE ALSO +.Xr biff 1 , +.Xr talk 1 , +.Xr write 1 +.Sh HISTORY +A +.Nm mesg +command appeared in +.At v6 . diff --git a/usr.bin/mesg/mesg.c b/usr.bin/mesg/mesg.c new file mode 100644 index 0000000..ad666f7 --- /dev/null +++ b/usr.bin/mesg/mesg.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * (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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mesg.c 8.2 (Berkeley) 1/21/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb; + char *tty; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + goto usage; + } + argc -= optind; + argv += optind; + + if ((tty = ttyname(STDERR_FILENO)) == NULL) + err(1, "ttyname"); + if (stat(tty, &sb) < 0) + err(1, "%s", tty); + + if (*argv == NULL) { + if (sb.st_mode & S_IWGRP) { + (void)fprintf(stderr, "is y\n"); + exit(0); + } + (void)fprintf(stderr, "is n\n"); + exit(1); + } + + switch (*argv[0]) { + case 'y': + if (chmod(tty, sb.st_mode | S_IWGRP) < 0) + err(1, "%s", tty); + exit(0); + case 'n': + if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) + err(1, "%s", tty); + exit(1); + } + +usage: (void)fprintf(stderr, "usage: mesg [y | n]\n"); + exit(2); +} diff --git a/usr.bin/mkdep/Makefile b/usr.bin/mkdep/Makefile new file mode 100644 index 0000000..61f62fd --- /dev/null +++ b/usr.bin/mkdep/Makefile @@ -0,0 +1,16 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +MAN1= mkdep.0 + +.if (${MACHINE} == "hp300" || ${MACHINE} == "i386" || \ + ${MACHINE} == "mips" || ${MACHINE} == "sparc") +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/mkdep.gcc.sh ${DESTDIR}/usr/bin/mkdep +.else +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/mkdep.sh ${DESTDIR}/usr/bin/mkdep +.endif + +.include diff --git a/usr.bin/mkdep/mkdep.1 b/usr.bin/mkdep/mkdep.1 new file mode 100644 index 0000000..5c62a6b --- /dev/null +++ b/usr.bin/mkdep/mkdep.1 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1987, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mkdep.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MKDEP 1 +.Os BSD 4.2 +.Sh NAME +.Nm mkdep +.Nd construct Makefile dependency list +.Sh SYNOPSIS +.Nm mkdep +.Op Fl ap +.Op Fl f Ar file +.Op Ar flags +.Ar file ... +.Sh DESCRIPTION +.Nm Mkdep +takes a set of flags for the C compiler and a list +of C source files as arguments and constructs a set of include +file dependencies which are written into the file ``.depend''. +An example of its use in a Makefile might be: +.Bd -literal -offset indent +CFLAGS= -O -I../include +SRCS= file1.c file2.c + +depend: + mkdep ${CFLAGS} ${SRCS} +.Ed +.Pp +where the macro SRCS is the list of C source files and the macro +CFLAGS is the list of flags for the C compiler. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Append to the output file, +so that multiple +.Nm mkdep Ns 's +may be run from a single Makefile. +.It Fl f +Write the include file dependencies to +.Ar file , +instead of the default ``.depend''. +.It Fl p +Cause +.Nm mkdep +to produce dependencies of the form: +.Bd -literal -offset indent +program: program.c +.Ed +.Pp +so that subsequent makes will produce +.Ar program +directly from its C module rather than using an intermediate +.Pa \&.o +module. +This is useful for programs whose source is contained in a single +module. +.El +.Sh SEE ALSO +.Xr cc 1 , +.Xr cpp 1 , +.Xr make 1 +.Sh FILES +.Bl -tag -width .depend -compact +.It Pa .depend +File containing list of dependencies. +.El +.Sh HISTORY +The +.Nm mkdep +command appeared in +.Bx 4.3 Tahoe . diff --git a/usr.bin/mkdep/mkdep.append b/usr.bin/mkdep/mkdep.append new file mode 100644 index 0000000..1c84dd1 --- /dev/null +++ b/usr.bin/mkdep/mkdep.append @@ -0,0 +1,123 @@ +#!/bin/sh - +# +# 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. +# +# @(#)mkdep.append 8.1 (Berkeley) 6/6/93 +# + +PATH=/bin:/usr/bin:/usr/ucb +export PATH + +MAKE=Makefile # default makefile name is "Makefile" + +while : + do case "$1" in + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f makefile] [flags] file ...' + exit 1 +fi + +if [ ! -w $MAKE ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cp $MAKE ${MAKE}.bak + +sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP + +cat << _EOF_ >> $TMP +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + +# If your compiler doesn't have -M, add it. If you can't, the next two +# lines will try and replace the "cc -M". The real problem is that this +# hack can't deal with anything that requires a search path, and doesn't +# even try for anything using bracket (<>) syntax. +# +# egrep '^#include[ ]*".*"' /dev/null $* | +# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | + +cc -M $* | +sed " + s; \./; ;g + $SED" | +awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } +} +END { + print rec +}' >> $TMP + +cat << _EOF_ >> $TMP + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp $TMP $MAKE +rm -f ${MAKE}.bak $TMP +exit 0 diff --git a/usr.bin/mkdep/mkdep.gcc.sh b/usr.bin/mkdep/mkdep.gcc.sh new file mode 100644 index 0000000..26f80d6 --- /dev/null +++ b/usr.bin/mkdep/mkdep.gcc.sh @@ -0,0 +1,93 @@ +#!/bin/sh - +# +# 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. +# +# @(#)mkdep.gcc.sh 8.1 (Berkeley) 6/6/93 +# + +PATH=/bin:/usr/bin:/usr/ucb +export PATH + +D=.depend # default dependency file is .depend +append=0 +pflag= + +while : + do case "$1" in + # -a appends to the depend file + -a) + append=1 + shift ;; + + # -f allows you to select a makefile name + -f) + D=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + pflag=p + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f depend_file] [cc_flags] file ...' + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +if [ x$pflag = x ]; then + cpp -M $* | sed -e 's; \./; ;g' > $TMP +else + cpp -M $* | sed -e 's;\.o :; :;' -e 's; \./; ;g' > $TMP +fi + +if [ $? != 0 ]; then + echo 'mkdep: compile failed.' + rm -f $TMP + exit 1 +fi + +if [ $append = 1 ]; then + cat $TMP >> $D + rm -f $TMP +else + mv $TMP $D +fi +exit 0 diff --git a/usr.bin/mkdep/mkdep.old.compiler b/usr.bin/mkdep/mkdep.old.compiler new file mode 100644 index 0000000..5c77773 --- /dev/null +++ b/usr.bin/mkdep/mkdep.old.compiler @@ -0,0 +1,143 @@ +#!/bin/sh - +# +# 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. +# +# @(#)mkdep.old.compiler 8.1 (Berkeley) 6/6/93 +# + +# This is a version of mkdep that works pretty well +# with compilers that don't have -M. +MAKE=Makefile # default makefile name is "Makefile" + +PATH=/bin:/usr/bin:/usr/ucb:/lib:/usr/lib + +INCL= + +while : + do case "$1" in + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f makefile] [flags] file ...' + exit 1 +fi + +if [ ! -w $MAKE ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cp $MAKE ${MAKE}.bak +sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP + +cat << _EOF_ >> $TMP +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + + +for i do + case "$i" in + -c|-M|-O) + ;; + -I*) + INCL="$INCL $i";; + -D*|-U*) + FLAGS="$FLAGS $i";; + *) + # assume source file + # put '$dep' in front of dependencies + dep=`echo "$i" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.o/'` + + # Find includes, remove leading numerics, remove ./, + # remove double quotes, and remove trailing numerics. + # Sort that, discarding duplicates, and add '$dep'. + cpp $INCL $FLAGS "$i" | sed -e ' + /^#/!d + s/# [0-9]* // + s,"./,", + s/"\(.*\)"/\1/ + s/ [ 0-9]*$//' | + sort -u | sed -e "s/^/$dep: /";; + esac +done | +sed " + s; \./; ;g + /\.c:$/d + $SED" | +awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } +} +END { + print rec +}' >> $TMP + +cat << _EOF_ >> $TMP + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp $TMP $MAKE +rm -f $TMP +exit 0 diff --git a/usr.bin/mkdep/mkdep.sh b/usr.bin/mkdep/mkdep.sh new file mode 100644 index 0000000..5344108 --- /dev/null +++ b/usr.bin/mkdep/mkdep.sh @@ -0,0 +1,111 @@ +#!/bin/sh - +# +# 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. +# +# @(#)mkdep.sh 8.1 (Berkeley) 6/6/93 +# + +PATH=/bin:/usr/bin:/usr/ucb:/usr/old/bin +export PATH + +D=.depend # default dependency file is .depend +append=0 + +while : + do case "$1" in + # -a appends to the depend file + -a) + append=1 + shift ;; + + # -f allows you to select a makefile name + -f) + D=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o ; ;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f depend_file] [cc_flags] file ...' + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cc -M $* | +sed " + s; \./; ;g + /\.c:$/d + $SED" | +awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } +} +END { + print rec +}' > $TMP + +if [ $? != 0 ]; then + echo 'mkdep: compile failed.' + rm -f $TMP + exit 1 +fi + +if [ $append = 1 ]; then + cat $TMP >> $D + rm -f $TMP +else + mv $TMP $D +fi +exit 0 diff --git a/usr.bin/mkdep/mkdep.ultrix b/usr.bin/mkdep/mkdep.ultrix new file mode 100644 index 0000000..8c48667 --- /dev/null +++ b/usr.bin/mkdep/mkdep.ultrix @@ -0,0 +1,124 @@ +#!/bin/sh - +# +# 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. +# +# @(#)mkdep.ultrix 8.1 (Berkeley) 6/6/93 +# + +PATH=/bin:/usr/bin:/usr/ucb +export PATH + +MAKE=Makefile # default makefile name is "Makefile" + +while : + do case "$1" in + # -f allows you to select a makefile name + -f) + MAKE=$2 + shift; shift ;; + + # the -p flag produces "program: program.c" style dependencies + # so .o's don't get produced + -p) + SED='s;\.o;;' + shift ;; + *) + break ;; + esac +done + +if [ $# = 0 ] ; then + echo 'usage: mkdep [-p] [-f makefile] [flags] file ...' + exit 1 +fi + +if [ ! -w $MAKE ]; then + echo "mkdep: no writeable file \"$MAKE\"" + exit 1 +fi + +TMP=/tmp/mkdep$$ + +trap 'rm -f $TMP ; exit 1' 1 2 3 13 15 + +cp $MAKE ${MAKE}.bak + +sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP + +cat << _EOF_ >> $TMP +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +_EOF_ + +# If your compiler doesn't have -M, add it. If you can't, the next two +# lines will try and replace the "cc -M". The real problem is that this +# hack can't deal with anything that requires a search path, and doesn't +# even try for anything using bracket (<>) syntax. +# +# egrep '^#include[ ]*".*"' /dev/null $* | +# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' | + +# Ultrix has already used -M for something else. +cc -Em $* | +sed " + s; \./; ;g + $SED" | +awk '{ + if ($1 != prev) { + if (rec != "") + print rec; + rec = $0; + prev = $1; + } + else { + if (length(rec $2) > 78) { + print rec; + rec = $0; + } + else + rec = rec " " $2 + } +} +END { + print rec +}' >> $TMP + +cat << _EOF_ >> $TMP + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +_EOF_ + +# copy to preserve permissions +cp $TMP $MAKE +rm -f ${MAKE}.bak $TMP +exit 0 diff --git a/usr.bin/mkfifo/Makefile b/usr.bin/mkfifo/Makefile new file mode 100644 index 0000000..fff2939 --- /dev/null +++ b/usr.bin/mkfifo/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkfifo + +.include diff --git a/usr.bin/mkfifo/mkfifo.1 b/usr.bin/mkfifo/mkfifo.1 new file mode 100644 index 0000000..f0607a7 --- /dev/null +++ b/usr.bin/mkfifo/mkfifo.1 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)mkfifo.1 8.2 (Berkeley) 1/5/94 +.\" +.Dd January 5, 1994 +.Dt MKFIFO 1 +.Os BSD 4.4 +.Sh NAME +.Nm mkfifo +.Nd make fifos +.Sh SYNOPSIS +.Nm mkfifo +.Ar fifo_name ... +.Sh DESCRIPTION +.Nm Mkfifo +creates the fifos requested, in the order specified, +using mode +.Li \&0777 . +.Pp +.Nm Mkfifo +requires write permission in the parent directory. +.Pp +.Nm Mkfifo +exits 0 if successful, and >0 if an error occurred. +.Sh STANDARDS +The +.Nm mkfifo +utility is expected to be +.St -p1003.2 +compliant. +.Sh SEE ALSO +.Xr mkdir 1 , +.Xr mknod 1 , +.Xr rm 1 , +.Xr mkfifo 2 +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/mkfifo/mkfifo.c b/usr.bin/mkfifo/mkfifo.c new file mode 100644 index 0000000..53b7435 --- /dev/null +++ b/usr.bin/mkfifo/mkfifo.c @@ -0,0 +1,82 @@ +/* + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkfifo.c 8.2 (Berkeley) 1/5/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + int ch, exitval; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + if (argv[0] == NULL) + usage(); + + for (exitval = 0; *argv != NULL; ++argv) + if (mkfifo(*argv, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { + warn("%s", *argv); + exitval = 1; + } + exit(exitval); +} + +usage() +{ + (void)fprintf(stderr, "usage: mkfifo fifoname ...\n"); + exit(1); +} diff --git a/usr.bin/mklocale/Japanese b/usr.bin/mklocale/Japanese new file mode 100644 index 0000000..55eb155 --- /dev/null +++ b/usr.bin/mklocale/Japanese @@ -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/usr.bin/mklocale/Makefile b/usr.bin/mklocale/Makefile new file mode 100644 index 0000000..ec108bd --- /dev/null +++ b/usr.bin/mklocale/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/7/93 + +PROG= mklocale +SRCS= yacc.c lex.c +CFLAGS+=-I. +CLEANFILES+=y.tab.h yacc.c lex.c + +.include diff --git a/usr.bin/mklocale/POSIX b/usr.bin/mklocale/POSIX new file mode 100644 index 0000000..ead0bc8 --- /dev/null +++ b/usr.bin/mklocale/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/usr.bin/mklocale/ldef.h b/usr.bin/mklocale/ldef.h new file mode 100644 index 0000000..95b51da --- /dev/null +++ b/usr.bin/mklocale/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/usr.bin/mklocale/lex.l b/usr.bin/mklocale/lex.l new file mode 100644 index 0000000..0e2f1a9 --- /dev/null +++ b/usr.bin/mklocale/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 +#include +#include + +#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/usr.bin/mklocale/mklocale.1 b/usr.bin/mklocale/mklocale.1 new file mode 100644 index 0000000..b0b0c62 --- /dev/null +++ b/usr.bin/mklocale/mklocale.1 @@ -0,0 +1,257 @@ +.\" Copyright (c) 1993, 1994 +.\" 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.2 (Berkeley) 4/18/94 +.\" +.Dd "April 18, 1994" +.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 "" +.It Dv +.Dv RUNE1 +is mapped to +.Dv RUNE2 . +.It Dv +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 representation of +.Dv RUNE1. +.It Dv MAPUPPER +Defines the toupper mappings. +.Dv RUNE2 +is the upper case representation 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/usr.bin/mklocale/yacc.y b/usr.bin/mklocale/yacc.y new file mode 100644 index 0000000..193b7b1 --- /dev/null +++ b/usr.bin/mklocale/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 +#include +#include +#include +#include + +#include "ldef.h" + +char *locale_file = ""; + +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 +%token LBRK +%token RBRK +%token THRU +%token MAPLOWER +%token MAPUPPER +%token DIGITMAP +%token LIST +%token VARIABLE +%token ENCODING +%token INVALID +%token STRING + +%type list +%type 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/usr.bin/mkstr/Makefile b/usr.bin/mkstr/Makefile new file mode 100644 index 0000000..c8af4d8 --- /dev/null +++ b/usr.bin/mkstr/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkstr + +.include diff --git a/usr.bin/mkstr/mkstr.1 b/usr.bin/mkstr/mkstr.1 new file mode 100644 index 0000000..f0493c1 --- /dev/null +++ b/usr.bin/mkstr/mkstr.1 @@ -0,0 +1,137 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mkstr.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MKSTR 1 +.Os +.Sh NAME +.Nm mkstr +.Nd create an error message file by massaging C source +.Sh SYNOPSIS +.Nm mkstr +.Op Fl +.Ar messagefile +.Ar prefix file ... +.Sh DESCRIPTION +.Nm Mkstr +creates files containing error messages extracted from C source, +and restructures the same C source, to utilize the created error message +file. +The intent of +.Nm mkstr +was to reduce the size of large programs and +reduce swapping (see +.Sx BUGS +section below). +.Pp +.Nm Mkstr +processes each of the specified +.Ar files , +placing a restructured version of the input in a file whose name +consists of the specified +.Ar prefix +and the original name. +A typical usage of +.Nm mkstr +is +.Bd -literal -offset indent +mkstr pistrings xx *.c +.Ed +.Pp +This command causes all the error messages from the C source +files in the current directory to be placed in the file +.Ar pistrings +and restructured copies of the sources to be placed in +files whose names are prefixed with +.Ar \&xx . +.Pp +Options: +.Bl -tag -width indent +.It Fl +Error messages are placed at the end of the specified +message file for recompiling part of a large +.Nm mkstr +ed +program. +.El +.Pp +.Nm mkstr +finds error messages in the source by +searching for the string +.Li \&`error("' +in the input stream. +Each time it occurs, the C string starting at the +.Sq \&"\& +is stored +in the message file followed by a null character and a new-line character; +The new source is restructured with +.Xr lseek 2 +pointers into the error message file for retrieval. +.Bd -literal -offset indent +char efilname = "/usr/lib/pi_strings"; +int efil = -1; + +error(a1, a2, a3, a4) +\&{ + char buf[256]; + + if (efil < 0) { + efil = open(efilname, 0); + if (efil < 0) { +oops: + perror(efilname); + exit 1 ; + } + } + if (lseek(efil, (long) a1, 0) \ read(efil, buf, 256) <= 0) + goto oops; + printf(buf, a2, a3, a4); +} +.Ed +.Sh SEE ALSO +.Xr lseek 2 , +.Xr xstr 1 +.Sh HISTORY +.Nm Mkstr +appeared in +.Bx 3.0 . +.Sh BUGS +.Nm mkstr +was intended for the limited architecture of the PDP 11 family. +Very few programs actually use it. The pascal interpreter, +.Xr \&pi 1 +and the editor, +.Xr \&ex 1 +are two programs that are built this way. +It is not an efficient method, the error messages +should be stored in the program text. diff --git a/usr.bin/mkstr/mkstr.c b/usr.bin/mkstr/mkstr.c new file mode 100644 index 0000000..c08857a --- /dev/null +++ b/usr.bin/mkstr/mkstr.c @@ -0,0 +1,310 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkstr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#define ungetchar(c) ungetc(c, stdin) + +long ftell(); +char *calloc(); +/* + * mkstr - create a string error message file by massaging C source + * + * Bill Joy UCB August 1977 + * + * Modified March 1978 to hash old messages to be able to recompile + * without addding messages to the message file (usually) + * + * Based on an earlier program conceived by Bill Joy and Chuck Haley + * + * Program to create a string error message file + * from a group of C programs. Arguments are the name + * of the file where the strings are to be placed, the + * prefix of the new files where the processed source text + * is to be placed, and the files to be processed. + * + * The program looks for 'error("' in the source stream. + * Whenever it finds this, the following characters from the '"' + * to a '"' are replaced by 'seekpt' where seekpt is a + * pointer into the error message file. + * If the '(' is not immediately followed by a '"' no change occurs. + * + * The optional '-' causes strings to be added at the end of the + * existing error message file for recompilation of single routines. + */ + + +FILE *mesgread, *mesgwrite; +char *progname; +char usagestr[] = "usage: %s [ - ] mesgfile prefix file ...\n"; +char name[100], *np; + +main(argc, argv) + int argc; + char *argv[]; +{ + char addon = 0; + + argc--, progname = *argv++; + if (argc > 1 && argv[0][0] == '-') + addon++, argc--, argv++; + if (argc < 3) + fprintf(stderr, usagestr, progname), exit(1); + mesgwrite = fopen(argv[0], addon ? "a" : "w"); + if (mesgwrite == NULL) + perror(argv[0]), exit(1); + mesgread = fopen(argv[0], "r"); + if (mesgread == NULL) + perror(argv[0]), exit(1); + inithash(); + argc--, argv++; + strcpy(name, argv[0]); + np = name + strlen(name); + argc--, argv++; + do { + strcpy(np, argv[0]); + if (freopen(name, "w", stdout) == NULL) + perror(name), exit(1); + if (freopen(argv[0], "r", stdin) == NULL) + perror(argv[0]), exit(1); + process(); + argc--, argv++; + } while (argc > 0); + exit(0); +} + +process() +{ + register char *cp; + register c; + + for (;;) { + c = getchar(); + if (c == EOF) + return; + if (c != 'e') { + putchar(c); + continue; + } + if (match("error(")) { + printf("error("); + c = getchar(); + if (c != '"') + putchar(c); + else + copystr(); + } + } +} + +match(ocp) + char *ocp; +{ + register char *cp; + register c; + + for (cp = ocp + 1; *cp; cp++) { + c = getchar(); + if (c != *cp) { + while (ocp < cp) + putchar(*ocp++); + ungetchar(c); + return (0); + } + } + return (1); +} + +copystr() +{ + register c, ch; + char buf[512]; + register char *cp = buf; + + for (;;) { + c = getchar(); + if (c == EOF) + break; + switch (c) { + + case '"': + *cp++ = 0; + goto out; + case '\\': + c = getchar(); + switch (c) { + + case 'b': + c = '\b'; + break; + case 't': + c = '\t'; + break; + case 'r': + c = '\r'; + break; + case 'n': + c = '\n'; + break; + case '\n': + continue; + case 'f': + c = '\f'; + break; + case '0': + c = 0; + break; + case '\\': + break; + default: + if (!octdigit(c)) + break; + c -= '0'; + ch = getchar(); + if (!octdigit(ch)) + break; + c <<= 7, c += ch - '0'; + ch = getchar(); + if (!octdigit(ch)) + break; + c <<= 3, c+= ch - '0', ch = -1; + break; + } + } + *cp++ = c; + } +out: + *cp = 0; + printf("%d", hashit(buf, 1, NULL)); +} + +octdigit(c) + char c; +{ + + return (c >= '0' && c <= '7'); +} + +inithash() +{ + char buf[512]; + int mesgpt = 0; + + rewind(mesgread); + while (fgetNUL(buf, sizeof buf, mesgread) != NULL) { + hashit(buf, 0, mesgpt); + mesgpt += strlen(buf) + 2; + } +} + +#define NBUCKETS 511 + +struct hash { + long hval; + unsigned hpt; + struct hash *hnext; +} *bucket[NBUCKETS]; + +hashit(str, really, fakept) + char *str; + char really; + unsigned fakept; +{ + int i; + register struct hash *hp; + char buf[512]; + long hashval = 0; + register char *cp; + + if (really) + fflush(mesgwrite); + for (cp = str; *cp;) + hashval = (hashval << 1) + *cp++; + i = hashval % NBUCKETS; + if (i < 0) + i += NBUCKETS; + if (really != 0) + for (hp = bucket[i]; hp != 0; hp = hp->hnext) + if (hp->hval == hashval) { + fseek(mesgread, (long) hp->hpt, 0); + fgetNUL(buf, sizeof buf, mesgread); +/* + fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf); +*/ + if (strcmp(buf, str) == 0) + break; + } + if (!really || hp == 0) { + hp = (struct hash *) calloc(1, sizeof *hp); + hp->hnext = bucket[i]; + hp->hval = hashval; + hp->hpt = really ? ftell(mesgwrite) : fakept; + if (really) { + fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite); + fwrite("\n", sizeof (char), 1, mesgwrite); + } + bucket[i] = hp; + } +/* + fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt); +*/ + return (hp->hpt); +} + +#include +#include + +fgetNUL(obuf, rmdr, file) + char *obuf; + register int rmdr; + FILE *file; +{ + register c; + register char *buf = obuf; + + while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) + *buf++ = c; + *buf++ = 0; + getc(file); + return ((feof(file) || ferror(file)) ? NULL : 1); +} diff --git a/usr.bin/more/Makefile b/usr.bin/more/Makefile new file mode 100644 index 0000000..58f9e81 --- /dev/null +++ b/usr.bin/more/Makefile @@ -0,0 +1,15 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= more +CFLAGS+=-I${.CURDIR} +SRCS= ch.c command.c decode.c help.c input.c line.c linenum.c main.c \ + option.c os.c output.c position.c prim.c screen.c signal.c tags.c \ + ttyin.c +DPADD= ${LIBTERM} ${LIBCOMPAT} +LDADD= -ltermcap -lcompat + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/more.help \ + ${DESTDIR}/usr/share/misc + +.include diff --git a/usr.bin/more/ch.c b/usr.bin/more/ch.c new file mode 100644 index 0000000..668e601 --- /dev/null +++ b/usr.bin/more/ch.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)ch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Low level character input from the input file. + * We use these special purpose routines which optimize moving + * both forward and backward from the current read pointer. + */ + +#include +#include +#include +#include +#include + +int file = -1; /* File descriptor of the input file */ + +/* + * Pool of buffers holding the most recently used blocks of the input file. + */ +struct buf { + struct buf *next, *prev; + long block; + int datasize; + char data[BUFSIZ]; +}; +int nbufs; + +/* + * The buffer pool is kept as a doubly-linked circular list, in order from + * most- to least-recently used. The circular list is anchored by buf_anchor. + */ +#define END_OF_CHAIN ((struct buf *)&buf_anchor) +#define buf_head buf_anchor.next +#define buf_tail buf_anchor.prev + +static struct { + struct buf *next, *prev; +} buf_anchor = { END_OF_CHAIN, END_OF_CHAIN }; + +extern int ispipe, cbufs, sigs; + +/* + * Current position in file. + * Stored as a block number and an offset into the block. + */ +static long ch_block; +static int ch_offset; + +/* Length of file, needed if input is a pipe. */ +static off_t ch_fsize; + +/* Number of bytes read, if input is standard input (a pipe). */ +static off_t last_piped_pos; + +/* + * Get the character pointed to by the read pointer. ch_get() is a macro + * which is more efficient to call than fch_get (the function), in the usual + * case that the block desired is at the head of the chain. + */ +#define ch_get() \ + ((buf_head->block == ch_block && \ + ch_offset < buf_head->datasize) ? \ + buf_head->data[ch_offset] : fch_get()) + +static +fch_get() +{ + extern int bs_mode; + register struct buf *bp; + register int n, ch; + register char *p, *t; + off_t pos, lseek(); + + /* look for a buffer holding the desired block. */ + for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next) + if (bp->block == ch_block) { + if (ch_offset >= bp->datasize) + /* + * Need more data in this buffer. + */ + goto read_more; + /* + * On a pipe, we don't sort the buffers LRU + * because this can cause gaps in the buffers. + * For example, suppose we've got 12 1K buffers, + * and a 15K input stream. If we read the first 12K + * sequentially, then jump to line 1, then jump to + * the end, the buffers have blocks 0,4,5,6,..,14. + * If we then jump to line 1 again and try to + * read sequentially, we're out of luck when we + * get to block 1 (we'd get the "pipe error" below). + * To avoid this, we only sort buffers on a pipe + * when we actually READ the data, not when we + * find it already buffered. + */ + if (ispipe) + return(bp->data[ch_offset]); + goto found; + } + /* + * Block is not in a buffer. Take the least recently used buffer + * and read the desired block into it. If the LRU buffer has data + * in it, and input is a pipe, then try to allocate a new buffer first. + */ + if (ispipe && buf_tail->block != (long)(-1)) + (void)ch_addbuf(1); + bp = buf_tail; + bp->block = ch_block; + bp->datasize = 0; + +read_more: + pos = (ch_block * BUFSIZ) + bp->datasize; + if (ispipe) { + /* + * The data requested should be immediately after + * the last data read from the pipe. + */ + if (pos != last_piped_pos) { + error("pipe error"); + quit(); + } + } else + (void)lseek(file, pos, L_SET); + + /* + * Read the block. + * If we read less than a full block, we just return the + * partial block and pick up the rest next time. + */ + n = iread(file, &bp->data[bp->datasize], BUFSIZ - bp->datasize); + if (n == READ_INTR) + return (EOI); + if (n < 0) { + error("read error"); + quit(); + } + if (ispipe) + last_piped_pos += n; + + p = &bp->data[bp->datasize]; + bp->datasize += n; + + /* + * Set an EOI marker in the buffered data itself. Then ensure the + * data is "clean": there are no extra EOI chars in the data and + * that the "meta" bit (the 0200 bit) is reset in each char; + * also translate \r\n sequences to \n if -u flag not set. + */ + if (n == 0) { + ch_fsize = pos; + bp->data[bp->datasize++] = EOI; + } + + if (bs_mode) { + for (p = &bp->data[bp->datasize]; --n >= 0;) { + *--p &= 0177; + if (*p == EOI) + *p = 0200; + } + } + else { + for (t = p; --n >= 0; ++p) { + ch = *p & 0177; + if (ch == '\r' && n && (p[1] & 0177) == '\n') { + ++p; + *t++ = '\n'; + } + else + *t++ = (ch == EOI) ? 0200 : ch; + } + if (p != t) { + bp->datasize -= p - t; + if (ispipe) + last_piped_pos -= p - t; + } + } + +found: + if (buf_head != bp) { + /* + * Move the buffer to the head of the buffer chain. + * This orders the buffer chain, most- to least-recently used. + */ + bp->next->prev = bp->prev; + bp->prev->next = bp->next; + + bp->next = buf_head; + bp->prev = END_OF_CHAIN; + buf_head->prev = bp; + buf_head = bp; + } + + if (ch_offset >= bp->datasize) + /* + * After all that, we still don't have enough data. + * Go back and try again. + */ + goto read_more; + + return(bp->data[ch_offset]); +} + +/* + * Determine if a specific block is currently in one of the buffers. + */ +static +buffered(block) + long block; +{ + register struct buf *bp; + + for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next) + if (bp->block == block) + return(1); + return(0); +} + +/* + * Seek to a specified position in the file. + * Return 0 if successful, non-zero if can't seek there. + */ +ch_seek(pos) + register off_t pos; +{ + long new_block; + + new_block = pos / BUFSIZ; + if (!ispipe || pos == last_piped_pos || buffered(new_block)) { + /* + * Set read pointer. + */ + ch_block = new_block; + ch_offset = pos % BUFSIZ; + return(0); + } + return(1); +} + +/* + * Seek to the end of the file. + */ +ch_end_seek() +{ + off_t ch_length(); + + if (!ispipe) + return(ch_seek(ch_length())); + + /* + * Do it the slow way: read till end of data. + */ + while (ch_forw_get() != EOI) + if (sigs) + return(1); + return(0); +} + +/* + * Seek to the beginning of the file, or as close to it as we can get. + * We may not be able to seek there if input is a pipe and the + * beginning of the pipe is no longer buffered. + */ +ch_beg_seek() +{ + register struct buf *bp, *firstbp; + + /* + * Try a plain ch_seek first. + */ + if (ch_seek((off_t)0) == 0) + return(0); + + /* + * Can't get to position 0. + * Look thru the buffers for the one closest to position 0. + */ + firstbp = bp = buf_head; + if (bp == END_OF_CHAIN) + return(1); + while ((bp = bp->next) != END_OF_CHAIN) + if (bp->block < firstbp->block) + firstbp = bp; + ch_block = firstbp->block; + ch_offset = 0; + return(0); +} + +/* + * Return the length of the file, if known. + */ +off_t +ch_length() +{ + off_t lseek(); + + if (ispipe) + return(ch_fsize); + return((off_t)(lseek(file, (off_t)0, L_XTND))); +} + +/* + * Return the current position in the file. + */ +off_t +ch_tell() +{ + return(ch_block * BUFSIZ + ch_offset); +} + +/* + * Get the current char and post-increment the read pointer. + */ +ch_forw_get() +{ + register int c; + + c = ch_get(); + if (c != EOI && ++ch_offset >= BUFSIZ) { + ch_offset = 0; + ++ch_block; + } + return(c); +} + +/* + * Pre-decrement the read pointer and get the new current char. + */ +ch_back_get() +{ + if (--ch_offset < 0) { + if (ch_block <= 0 || (ispipe && !buffered(ch_block-1))) { + ch_offset = 0; + return(EOI); + } + ch_offset = BUFSIZ - 1; + ch_block--; + } + return(ch_get()); +} + +/* + * Allocate buffers. + * Caller wants us to have a total of at least want_nbufs buffers. + * keep==1 means keep the data in the current buffers; + * otherwise discard the old data. + */ +ch_init(want_nbufs, keep) + int want_nbufs; + int keep; +{ + register struct buf *bp; + char message[80]; + + cbufs = nbufs; + if (nbufs < want_nbufs && ch_addbuf(want_nbufs - nbufs)) { + /* + * Cannot allocate enough buffers. + * If we don't have ANY, then quit. + * Otherwise, just report the error and return. + */ + (void)sprintf(message, "cannot allocate %d buffers", + want_nbufs - nbufs); + error(message); + if (nbufs == 0) + quit(); + return; + } + + if (keep) + return; + + /* + * We don't want to keep the old data, + * so initialize all the buffers now. + */ + for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next) + bp->block = (long)(-1); + last_piped_pos = (off_t)0; + ch_fsize = NULL_POSITION; + (void)ch_seek((off_t)0); +} + +/* + * Allocate some new buffers. + * The buffers are added to the tail of the buffer chain. + */ +ch_addbuf(nnew) + int nnew; +{ + register struct buf *bp; + register struct buf *newbufs; + char *calloc(); + + /* + * We don't have enough buffers. + * Allocate some new ones. + */ + newbufs = (struct buf *)calloc((u_int)nnew, sizeof(struct buf)); + if (newbufs == NULL) + return(1); + + /* + * Initialize the new buffers and link them together. + * Link them all onto the tail of the buffer list. + */ + nbufs += nnew; + cbufs = nbufs; + for (bp = &newbufs[0]; bp < &newbufs[nnew]; bp++) { + bp->next = bp + 1; + bp->prev = bp - 1; + bp->block = (long)(-1); + } + newbufs[nnew-1].next = END_OF_CHAIN; + newbufs[0].prev = buf_tail; + buf_tail->next = &newbufs[0]; + buf_tail = &newbufs[nnew-1]; + return(0); +} diff --git a/usr.bin/more/command.c b/usr.bin/more/command.c new file mode 100644 index 0000000..51f5847 --- /dev/null +++ b/usr.bin/more/command.c @@ -0,0 +1,655 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)command.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "pathnames.h" + +#define NO_MCA 0 +#define MCA_DONE 1 +#define MCA_MORE 2 + +extern int erase_char, kill_char, werase_char; +extern int ispipe; +extern int sigs; +extern int quit_at_eof; +extern int hit_eof; +extern int sc_width; +extern int sc_height; +extern int sc_window; +extern int curr_ac; +extern int ac; +extern int quitting; +extern int scroll; +extern int screen_trashed; /* The screen has been overwritten */ + +static char cmdbuf[120]; /* Buffer for holding a multi-char command */ +static char *cp; /* Pointer into cmdbuf */ +static int cmd_col; /* Current column of the multi-char command */ +static int longprompt; /* if stat command instead of prompt */ +static int mca; /* The multicharacter command (action) */ +static int last_mca; /* The previous mca */ +static int number; /* The number typed by the user */ +static int wsearch; /* Search for matches (1) or non-matches (0) */ + +#define CMD_RESET cp = cmdbuf /* reset command buffer to empty */ +#define CMD_EXEC lower_left(); flush() + +/* backspace in command buffer. */ +static +cmd_erase() +{ + /* + * backspace past beginning of the string: this usually means + * abort the command. + */ + if (cp == cmdbuf) + return(1); + + /* erase an extra character, for the carat. */ + if (CONTROL_CHAR(*--cp)) { + backspace(); + --cmd_col; + } + + backspace(); + --cmd_col; + return(0); +} + +/* set up the display to start a new multi-character command. */ +start_mca(action, prompt) + int action; + char *prompt; +{ + lower_left(); + clear_eol(); + putstr(prompt); + cmd_col = strlen(prompt); + mca = action; +} + +/* + * process a single character of a multi-character command, such as + * a number, or the pattern of a search command. + */ +static +cmd_char(c) + int c; +{ + if (c == erase_char) + return(cmd_erase()); + /* in this order, in case werase == erase_char */ + if (c == werase_char) { + if (cp > cmdbuf) { + while (isspace(cp[-1]) && !cmd_erase()); + while (!isspace(cp[-1]) && !cmd_erase()); + while (isspace(cp[-1]) && !cmd_erase()); + } + return(cp == cmdbuf); + } + if (c == kill_char) { + while (!cmd_erase()); + return(1); + } + /* + * No room in the command buffer, or no room on the screen; + * {{ Could get fancy here; maybe shift the displayed line + * and make room for more chars, like ksh. }} + */ + if (cp >= &cmdbuf[sizeof(cmdbuf)-1] || cmd_col >= sc_width-3) + bell(); + else { + *cp++ = c; + if (CONTROL_CHAR(c)) { + putchr('^'); + cmd_col++; + c = CARAT_CHAR(c); + } + putchr(c); + cmd_col++; + } + return(0); +} + +prompt() +{ + extern int linenums, short_file; + extern char *current_name, *firstsearch, *next_name; + off_t len, pos, ch_length(), position(), forw_line(); + char pbuf[40]; + + /* + * if nothing is displayed yet, display starting from line 1; + * if search string provided, go there instead. + */ + if (position(TOP) == NULL_POSITION) { + if (forw_line((off_t)0) == NULL_POSITION) + return(0); + if (!firstsearch || !search(1, firstsearch, 1, 1)) + jump_back(1); + } + else if (screen_trashed) + repaint(); + + /* if no -e flag and we've hit EOF on the last file, quit. */ + if ((!quit_at_eof || short_file) && hit_eof && curr_ac + 1 >= ac) + quit(); + + /* select the proper prompt and display it. */ + lower_left(); + clear_eol(); + if (longprompt) { + so_enter(); + putstr(current_name); + putstr(":"); + if (!ispipe) { + (void)sprintf(pbuf, " file %d/%d", curr_ac + 1, ac); + putstr(pbuf); + } + if (linenums) { + (void)sprintf(pbuf, " line %d", currline(BOTTOM)); + putstr(pbuf); + } + if ((pos = position(BOTTOM)) != NULL_POSITION) { + (void)sprintf(pbuf, " byte %qd", pos); + putstr(pbuf); + if (!ispipe && (len = ch_length())) { + (void)sprintf(pbuf, "/%qd pct %qd%%", + len, ((100 * pos) / len)); + putstr(pbuf); + } + } + so_exit(); + longprompt = 0; + } + else { + so_enter(); + putstr(current_name); + if (hit_eof) + if (next_name) { + putstr(": END (next file: "); + putstr(next_name); + putstr(")"); + } + else + putstr(": END"); + else if (!ispipe && + (pos = position(BOTTOM)) != NULL_POSITION && + (len = ch_length())) { + (void)sprintf(pbuf, " (%qd%%)", ((100 * pos) / len)); + putstr(pbuf); + } + so_exit(); + } + return(1); +} + +/* get command character. */ +static +getcc() +{ + extern int cmdstack; + int ch; + off_t position(); + + /* left over from error() routine. */ + if (cmdstack) { + ch = cmdstack; + cmdstack = NULL; + return(ch); + } + if (cp > cmdbuf && position(TOP) == NULL_POSITION) { + /* + * Command is incomplete, so try to complete it. + * There are only two cases: + * 1. We have "/string" but no newline. Add the \n. + * 2. We have a number but no command. Treat as #g. + * (This is all pretty hokey.) + */ + if (mca != A_DIGIT) + /* Not a number; must be search string */ + return('\n'); + else + /* A number; append a 'g' */ + return('g'); + } + return(getchr()); +} + +/* execute a multicharacter command. */ +static +exec_mca() +{ + extern int file; + extern char *tagfile; + register char *p; + char *glob(); + + *cp = '\0'; + CMD_EXEC; + switch (mca) { + case A_F_SEARCH: + (void)search(1, cmdbuf, number, wsearch); + break; + case A_B_SEARCH: + (void)search(0, cmdbuf, number, wsearch); + break; + case A_EXAMINE: + for (p = cmdbuf; isspace(*p); ++p); + (void)edit(glob(p)); + break; + case A_TAGFILE: + for (p = cmdbuf; isspace(*p); ++p); + findtag(p); + if (tagfile == NULL) + break; + if (edit(tagfile)) + (void)tagsearch(); + break; + } +} + +/* add a character to a multi-character command. */ +static +mca_char(c) + int c; +{ + switch (mca) { + case 0: /* not in a multicharacter command. */ + case A_PREFIX: /* in the prefix of a command. */ + return(NO_MCA); + case A_DIGIT: + /* + * Entering digits of a number. + * Terminated by a non-digit. + */ + if (!isascii(c) || !isdigit(c) && + c != erase_char && c != kill_char && c != werase_char) { + /* + * Not part of the number. + * Treat as a normal command character. + */ + *cp = '\0'; + number = atoi(cmdbuf); + CMD_RESET; + mca = 0; + return(NO_MCA); + } + break; + } + + /* + * Any other multicharacter command + * is terminated by a newline. + */ + if (c == '\n' || c == '\r') { + exec_mca(); + return(MCA_DONE); + } + + /* append the char to the command buffer. */ + if (cmd_char(c)) + return(MCA_DONE); + + return(MCA_MORE); +} + +/* + * Main command processor. + * Accept and execute commands until a quit command, then return. + */ +commands() +{ + register int c; + register int action; + + last_mca = 0; + scroll = (sc_height + 1) / 2; + + for (;;) { + mca = 0; + number = 0; + + /* + * See if any signals need processing. + */ + if (sigs) { + psignals(); + if (quitting) + quit(); + } + /* + * Display prompt and accept a character. + */ + CMD_RESET; + if (!prompt()) { + next_file(1); + continue; + } + noprefix(); + c = getcc(); + +again: if (sigs) + continue; + + /* + * If we are in a multicharacter command, call mca_char. + * Otherwise we call cmd_decode to determine the + * action to be performed. + */ + if (mca) + switch (mca_char(c)) { + case MCA_MORE: + /* + * Need another character. + */ + c = getcc(); + goto again; + case MCA_DONE: + /* + * Command has been handled by mca_char. + * Start clean with a prompt. + */ + continue; + case NO_MCA: + /* + * Not a multi-char command + * (at least, not anymore). + */ + break; + } + + /* decode the command character and decide what to do. */ + switch (action = cmd_decode(c)) { + case A_DIGIT: /* first digit of a number */ + start_mca(A_DIGIT, ":"); + goto again; + case A_F_SCREEN: /* forward one screen */ + CMD_EXEC; + if (number <= 0 && (number = sc_window) <= 0) + number = sc_height - 1; + forward(number, 1); + break; + case A_B_SCREEN: /* backward one screen */ + CMD_EXEC; + if (number <= 0 && (number = sc_window) <= 0) + number = sc_height - 1; + backward(number, 1); + break; + case A_F_LINE: /* forward N (default 1) line */ + CMD_EXEC; + forward(number <= 0 ? 1 : number, 0); + break; + case A_B_LINE: /* backward N (default 1) line */ + CMD_EXEC; + backward(number <= 0 ? 1 : number, 0); + break; + case A_F_SCROLL: /* forward N lines */ + CMD_EXEC; + if (number > 0) + scroll = number; + forward(scroll, 0); + break; + case A_B_SCROLL: /* backward N lines */ + CMD_EXEC; + if (number > 0) + scroll = number; + backward(scroll, 0); + break; + case A_FREPAINT: /* flush buffers and repaint */ + if (!ispipe) { + ch_init(0, 0); + clr_linenum(); + } + /* FALLTHROUGH */ + case A_REPAINT: /* repaint the screen */ + CMD_EXEC; + repaint(); + break; + case A_GOLINE: /* go to line N, default 1 */ + CMD_EXEC; + if (number <= 0) + number = 1; + jump_back(number); + break; + case A_PERCENT: /* go to percent of file */ + CMD_EXEC; + if (number < 0) + number = 0; + else if (number > 100) + number = 100; + jump_percent(number); + break; + case A_GOEND: /* go to line N, default end */ + CMD_EXEC; + if (number <= 0) + jump_forw(); + else + jump_back(number); + break; + case A_STAT: /* print file name, etc. */ + longprompt = 1; + continue; + case A_QUIT: /* exit */ + quit(); + case A_F_SEARCH: /* search for a pattern */ + case A_B_SEARCH: + if (number <= 0) + number = 1; + start_mca(action, (action==A_F_SEARCH) ? "/" : "?"); + last_mca = mca; + wsearch = 1; + c = getcc(); + if (c == '!') { + /* + * Invert the sense of the search; set wsearch + * to 0 and get a new character for the start + * of the pattern. + */ + start_mca(action, + (action == A_F_SEARCH) ? "!/" : "!?"); + wsearch = 0; + c = getcc(); + } + goto again; + case A_AGAIN_SEARCH: /* repeat previous search */ + if (number <= 0) + number = 1; + if (wsearch) + start_mca(last_mca, + (last_mca == A_F_SEARCH) ? "/" : "?"); + else + start_mca(last_mca, + (last_mca == A_F_SEARCH) ? "!/" : "!?"); + CMD_EXEC; + (void)search(mca == A_F_SEARCH, (char *)NULL, + number, wsearch); + break; + case A_HELP: /* help */ + lower_left(); + clear_eol(); + putstr("help"); + CMD_EXEC; + help(); + break; + case A_TAGFILE: /* tag a new file */ + CMD_RESET; + start_mca(A_TAGFILE, "Tag: "); + c = getcc(); + goto again; + case A_FILE_LIST: /* show list of file names */ + CMD_EXEC; + showlist(); + repaint(); + break; + case A_EXAMINE: /* edit a new file */ + CMD_RESET; + start_mca(A_EXAMINE, "Examine: "); + c = getcc(); + goto again; + case A_VISUAL: /* invoke the editor */ + if (ispipe) { + error("Cannot edit standard input"); + break; + } + CMD_EXEC; + editfile(); + ch_init(0, 0); + clr_linenum(); + break; + case A_NEXT_FILE: /* examine next file */ + if (number <= 0) + number = 1; + next_file(number); + break; + case A_PREV_FILE: /* examine previous file */ + if (number <= 0) + number = 1; + prev_file(number); + break; + case A_SETMARK: /* set a mark */ + lower_left(); + clear_eol(); + start_mca(A_SETMARK, "mark: "); + c = getcc(); + if (c == erase_char || c == kill_char) + break; + setmark(c); + break; + case A_GOMARK: /* go to mark */ + lower_left(); + clear_eol(); + start_mca(A_GOMARK, "goto mark: "); + c = getcc(); + if (c == erase_char || c == kill_char) + break; + gomark(c); + break; + case A_PREFIX: + /* + * The command is incomplete (more chars are needed). + * Display the current char so the user knows what's + * going on and get another character. + */ + if (mca != A_PREFIX) + start_mca(A_PREFIX, ""); + if (CONTROL_CHAR(c)) { + putchr('^'); + c = CARAT_CHAR(c); + } + putchr(c); + c = getcc(); + goto again; + default: + bell(); + break; + } + } +} + +editfile() +{ + extern char *current_file; + static int dolinenumber; + static char *editor; + int c; + char buf[MAXPATHLEN * 2 + 20], *getenv(); + + if (editor == NULL) { + editor = getenv("EDITOR"); + /* pass the line number to vi */ + if (editor == NULL || *editor == '\0') { + editor = _PATH_VI; + dolinenumber = 1; + } + else + dolinenumber = 0; + } + if (dolinenumber && (c = currline(MIDDLE))) + (void)sprintf(buf, "%s +%d %s", editor, c, current_file); + else + (void)sprintf(buf, "%s %s", editor, current_file); + lsystem(buf); +} + +showlist() +{ + extern int sc_width; + extern char **av; + register int indx, width; + int len; + char *p; + + if (ac <= 0) { + error("No files provided as arguments."); + return; + } + for (width = indx = 0; indx < ac;) { + p = strcmp(av[indx], "-") ? av[indx] : "stdin"; + len = strlen(p) + 1; + if (curr_ac == indx) + len += 2; + if (width + len + 1 >= sc_width) { + if (!width) { + if (curr_ac == indx) + putchr('['); + putstr(p); + if (curr_ac == indx) + putchr(']'); + ++indx; + } + width = 0; + putchr('\n'); + continue; + } + if (width) + putchr(' '); + if (curr_ac == indx) + putchr('['); + putstr(p); + if (curr_ac == indx) + putchr(']'); + width += len; + ++indx; + } + putchr('\n'); + error((char *)NULL); +} diff --git a/usr.bin/more/decode.c b/usr.bin/more/decode.c new file mode 100644 index 0000000..83fa624 --- /dev/null +++ b/usr.bin/more/decode.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)decode.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines to decode user commands. + * + * This is all table driven. + * A command table is a sequence of command descriptors. + * Each command descriptor is a sequence of bytes with the following format: + * ...<0> + * The characters c1,c2,...,cN are the command string; that is, + * the characters which the user must type. + * It is terminated by a null <0> byte. + * The byte after the null byte is the action code associated + * with the command string. + * + * The default commands are described by cmdtable. + */ + +#include +#include +#include +#include + +/* + * Command table is ordered roughly according to expected + * frequency of use, so the common commands are near the beginning. + */ +#define CONTROL(c) ((c)&037) + +static char cmdtable[] = { + '\r',0, A_F_LINE, + '\n',0, A_F_LINE, + 'j',0, A_F_LINE, + 'k',0, A_B_LINE, + 'd',0, A_F_SCROLL, + CONTROL('D'),0, A_F_SCROLL, + 'u',0, A_B_SCROLL, + CONTROL('U'),0, A_B_SCROLL, + ' ',0, A_F_SCREEN, + 'f',0, A_F_SCREEN, + CONTROL('F'),0, A_F_SCREEN, + 'b',0, A_B_SCREEN, + CONTROL('B'),0, A_B_SCREEN, + 'R',0, A_FREPAINT, + 'r',0, A_REPAINT, + CONTROL('L'),0, A_REPAINT, + 'g',0, A_GOLINE, + 'p',0, A_PERCENT, + '%',0, A_PERCENT, + 'G',0, A_GOEND, + '0',0, A_DIGIT, + '1',0, A_DIGIT, + '2',0, A_DIGIT, + '3',0, A_DIGIT, + '4',0, A_DIGIT, + '5',0, A_DIGIT, + '6',0, A_DIGIT, + '7',0, A_DIGIT, + '8',0, A_DIGIT, + '9',0, A_DIGIT, + + '=',0, A_STAT, + CONTROL('G'),0, A_STAT, + '/',0, A_F_SEARCH, + '?',0, A_B_SEARCH, + 'n',0, A_AGAIN_SEARCH, + 'm',0, A_SETMARK, + '\'',0, A_GOMARK, + 'E',0, A_EXAMINE, + 'N',0, A_NEXT_FILE, + ':','n',0, A_NEXT_FILE, + 'P',0, A_PREV_FILE, + ':','p',0, A_PREV_FILE, + 'v',0, A_VISUAL, + + 'h',0, A_HELP, + 'q',0, A_QUIT, + ':','q',0, A_QUIT, + ':','t',0, A_TAGFILE, + ':', 'a', 0, A_FILE_LIST, + 'Z','Z',0, A_QUIT, +}; + +char *cmdendtable = cmdtable + sizeof(cmdtable); + +#define MAX_CMDLEN 16 + +static char kbuf[MAX_CMDLEN+1]; +static char *kp = kbuf; + +/* + * Indicate that we're not in a prefix command + * by resetting the command buffer pointer. + */ +noprefix() +{ + kp = kbuf; +} + +/* + * Decode a command character and return the associated action. + */ +cmd_decode(c) + int c; +{ + register int action = A_INVALID; + + /* + * Append the new command character to the command string in kbuf. + */ + *kp++ = c; + *kp = '\0'; + + action = cmd_search(cmdtable, cmdendtable); + + /* This is not a prefix character. */ + if (action != A_PREFIX) + noprefix(); + return(action); +} + +/* + * Search a command table for the current command string (in kbuf). + */ +cmd_search(table, endtable) + char *table; + char *endtable; +{ + register char *p, *q; + + for (p = table, q = kbuf; p < endtable; p++, q++) { + if (*p == *q) { + /* + * Current characters match. + * If we're at the end of the string, we've found it. + * Return the action code, which is the character + * after the null at the end of the string + * in the command table. + */ + if (*p == '\0') + return(p[1]); + } + else if (*q == '\0') { + /* + * Hit the end of the user's command, + * but not the end of the string in the command table. + * The user's command is incomplete. + */ + return(A_PREFIX); + } else { + /* + * Not a match. + * Skip ahead to the next command in the + * command table, and reset the pointer + * to the user's command. + */ + while (*p++ != '\0'); + q = kbuf-1; + } + } + /* + * No match found in the entire command table. + */ + return(A_INVALID); +} diff --git a/usr.bin/more/help.c b/usr.bin/more/help.c new file mode 100644 index 0000000..eeb3795 --- /dev/null +++ b/usr.bin/more/help.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)help.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include "pathnames.h" + +help() +{ + char cmd[MAXPATHLEN + 20]; + + (void)sprintf(cmd, "-more %s", _PATH_HELPFILE); + lsystem(cmd); +} diff --git a/usr.bin/more/input.c b/usr.bin/more/input.c new file mode 100644 index 0000000..521bc53 --- /dev/null +++ b/usr.bin/more/input.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)input.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * High level routines dealing with getting lines of input + * from the file being viewed. + * + * When we speak of "lines" here, we mean PRINTABLE lines; + * lines processed with respect to the screen width. + * We use the term "raw line" to refer to lines simply + * delimited by newlines; not processed with respect to screen width. + */ + +#include +#include + +extern int squeeze; +extern int sigs; +extern char *line; + +off_t ch_tell(); + +/* + * Get the next line. + * A "current" position is passed and a "new" position is returned. + * The current position is the position of the first character of + * a line. The new position is the position of the first character + * of the NEXT line. The line obtained is the line starting at curr_pos. + */ +off_t +forw_line(curr_pos) + off_t curr_pos; +{ + off_t new_pos; + register int c; + + if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) + return (NULL_POSITION); + + c = ch_forw_get(); + if (c == EOI) + return (NULL_POSITION); + + prewind(); + for (;;) + { + if (sigs) + return (NULL_POSITION); + if (c == '\n' || c == EOI) + { + /* + * End of the line. + */ + new_pos = ch_tell(); + break; + } + + /* + * Append the char to the line and get the next char. + */ + if (pappend(c)) + { + /* + * The char won't fit in the line; the line + * is too long to print in the screen width. + * End the line here. + */ + new_pos = ch_tell() - 1; + break; + } + c = ch_forw_get(); + } + (void) pappend('\0'); + + if (squeeze && *line == '\0') + { + /* + * This line is blank. + * Skip down to the last contiguous blank line + * and pretend it is the one which we are returning. + */ + while ((c = ch_forw_get()) == '\n') + if (sigs) + return (NULL_POSITION); + if (c != EOI) + (void) ch_back_get(); + new_pos = ch_tell(); + } + + return (new_pos); +} + +/* + * Get the previous line. + * A "current" position is passed and a "new" position is returned. + * The current position is the position of the first character of + * a line. The new position is the position of the first character + * of the PREVIOUS line. The line obtained is the one starting at new_pos. + */ +off_t +back_line(curr_pos) + off_t curr_pos; +{ + off_t new_pos, begin_new_pos; + int c; + + if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || + ch_seek(curr_pos-1)) + return (NULL_POSITION); + + if (squeeze) + { + /* + * Find out if the "current" line was blank. + */ + (void) ch_forw_get(); /* Skip the newline */ + c = ch_forw_get(); /* First char of "current" line */ + (void) ch_back_get(); /* Restore our position */ + (void) ch_back_get(); + + if (c == '\n') + { + /* + * The "current" line was blank. + * Skip over any preceeding blank lines, + * since we skipped them in forw_line(). + */ + while ((c = ch_back_get()) == '\n') + if (sigs) + return (NULL_POSITION); + if (c == EOI) + return (NULL_POSITION); + (void) ch_forw_get(); + } + } + + /* + * Scan backwards until we hit the beginning of the line. + */ + for (;;) + { + if (sigs) + return (NULL_POSITION); + c = ch_back_get(); + if (c == '\n') + { + /* + * This is the newline ending the previous line. + * We have hit the beginning of the line. + */ + new_pos = ch_tell() + 1; + break; + } + if (c == EOI) + { + /* + * We have hit the beginning of the file. + * This must be the first line in the file. + * This must, of course, be the beginning of the line. + */ + new_pos = ch_tell(); + break; + } + } + + /* + * Now scan forwards from the beginning of this line. + * We keep discarding "printable lines" (based on screen width) + * until we reach the curr_pos. + * + * {{ This algorithm is pretty inefficient if the lines + * are much longer than the screen width, + * but I don't know of any better way. }} + */ + if (ch_seek(new_pos)) + return (NULL_POSITION); + loop: + begin_new_pos = new_pos; + prewind(); + + do + { + c = ch_forw_get(); + if (c == EOI || sigs) + return (NULL_POSITION); + new_pos++; + if (c == '\n') + break; + if (pappend(c)) + { + /* + * Got a full printable line, but we haven't + * reached our curr_pos yet. Discard the line + * and start a new one. + */ + (void) pappend('\0'); + (void) ch_back_get(); + new_pos--; + goto loop; + } + } while (new_pos < curr_pos); + + (void) pappend('\0'); + + return (begin_new_pos); +} diff --git a/usr.bin/more/less.h b/usr.bin/more/less.h new file mode 100644 index 0000000..70de6de --- /dev/null +++ b/usr.bin/more/less.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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. + * + * @(#)less.h 8.1 (Berkeley) 6/6/93 + */ + +#define RECOMP + +#define NULL_POSITION ((off_t)(-1)) + +#define EOI (0) +#define READ_INTR (-2) + +/* Special chars used to tell put_line() to do something special */ +#define UL_CHAR '\201' /* Enter underline mode */ +#define UE_CHAR '\202' /* Exit underline mode */ +#define BO_CHAR '\203' /* Enter boldface mode */ +#define BE_CHAR '\204' /* Exit boldface mode */ + +#define CONTROL_CHAR(c) (iscntrl(c)) +#define CARAT_CHAR(c) ((c == '\177') ? '?' : (c | 0100)) + +#define TOP (0) +#define TOP_PLUS_ONE (1) +#define BOTTOM (-1) +#define BOTTOM_PLUS_ONE (-2) +#define MIDDLE (-3) + +#define A_INVALID -1 + +#define A_AGAIN_SEARCH 1 +#define A_B_LINE 2 +#define A_B_SCREEN 3 +#define A_B_SCROLL 4 +#define A_B_SEARCH 5 +#define A_DIGIT 6 +#define A_EXAMINE 7 +#define A_FREPAINT 8 +#define A_F_LINE 9 +#define A_F_SCREEN 10 +#define A_F_SCROLL 11 +#define A_F_SEARCH 12 +#define A_GOEND 13 +#define A_GOLINE 14 +#define A_GOMARK 15 +#define A_HELP 16 +#define A_NEXT_FILE 17 +#define A_PERCENT 18 +#define A_PREFIX 19 +#define A_PREV_FILE 20 +#define A_QUIT 21 +#define A_REPAINT 22 +#define A_SETMARK 23 +#define A_STAT 24 +#define A_VISUAL 25 +#define A_TAGFILE 26 +#define A_FILE_LIST 27 diff --git a/usr.bin/more/line.c b/usr.bin/more/line.c new file mode 100644 index 0000000..7634f35 --- /dev/null +++ b/usr.bin/more/line.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)line.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines to manipulate the "line buffer". + * The line buffer holds a line of output as it is being built + * in preparation for output to the screen. + * We keep track of the PRINTABLE length of the line as it is being built. + */ + +#include +#include +#include + +static char linebuf[1024]; /* Buffer which holds the current output line */ +static char *curr; /* Pointer into linebuf */ +static int column; /* Printable length, accounting for + backspaces, etc. */ +/* + * A ridiculously complex state machine takes care of backspaces. The + * complexity arises from the attempt to deal with all cases, especially + * involving long lines with underlining, boldfacing or whatever. There + * are still some cases which will break it. + * + * There are four states: + * LN_NORMAL is the normal state (not in underline mode). + * LN_UNDERLINE means we are in underline mode. We expect to get + * either a sequence like "_\bX" or "X\b_" to continue + * underline mode, or anything else to end underline mode. + * LN_BOLDFACE means we are in boldface mode. We expect to get sequences + * like "X\bX\b...X\bX" to continue boldface mode, or anything + * else to end boldface mode. + * LN_UL_X means we are one character after LN_UNDERLINE + * (we have gotten the '_' in "_\bX" or the 'X' in "X\b_"). + * LN_UL_XB means we are one character after LN_UL_X + * (we have gotten the backspace in "_\bX" or "X\b_"; + * we expect one more ordinary character, + * which will put us back in state LN_UNDERLINE). + * LN_BO_X means we are one character after LN_BOLDFACE + * (we have gotten the 'X' in "X\bX"). + * LN_BO_XB means we are one character after LN_BO_X + * (we have gotten the backspace in "X\bX"; + * we expect one more 'X' which will put us back + * in LN_BOLDFACE). + */ +static int ln_state; /* Currently in normal/underline/bold/etc mode? */ +#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */ +#define LN_UNDERLINE 1 /* In underline, need next char */ +#define LN_UL_X 2 /* In underline, got char, need \b */ +#define LN_UL_XB 3 /* In underline, got char & \b, need one more */ +#define LN_BOLDFACE 4 /* In boldface, need next char */ +#define LN_BO_X 5 /* In boldface, got char, need \b */ +#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */ + +char *line; /* Pointer to the current line. + Usually points to linebuf. */ + +extern int bs_mode; +extern int tabstop; +extern int bo_width, be_width; +extern int ul_width, ue_width; +extern int sc_width, sc_height; + +/* + * Rewind the line buffer. + */ +prewind() +{ + line = curr = linebuf; + ln_state = LN_NORMAL; + column = 0; +} + +/* + * Append a character to the line buffer. + * Expand tabs into spaces, handle underlining, boldfacing, etc. + * Returns 0 if ok, 1 if couldn't fit in buffer. + */ +#define NEW_COLUMN(addon) \ + if (column + addon + (ln_state ? ue_width : 0) > sc_width) \ + return(1); \ + else \ + column += addon + +pappend(c) + int c; +{ + if (c == '\0') { + /* + * Terminate any special modes, if necessary. + * Append a '\0' to the end of the line. + */ + switch (ln_state) { + case LN_UL_X: + curr[0] = curr[-1]; + curr[-1] = UE_CHAR; + curr++; + break; + case LN_BO_X: + curr[0] = curr[-1]; + curr[-1] = BE_CHAR; + curr++; + break; + case LN_UL_XB: + case LN_UNDERLINE: + *curr++ = UE_CHAR; + break; + case LN_BO_XB: + case LN_BOLDFACE: + *curr++ = BE_CHAR; + break; + } + ln_state = LN_NORMAL; + *curr = '\0'; + return(0); + } + + if (curr > linebuf + sizeof(linebuf) - 12) + /* + * Almost out of room in the line buffer. + * Don't take any chances. + * {{ Linebuf is supposed to be big enough that this + * will never happen, but may need to be made + * bigger for wide screens or lots of backspaces. }} + */ + return(1); + + if (!bs_mode) { + /* + * Advance the state machine. + */ + switch (ln_state) { + case LN_NORMAL: + if (curr <= linebuf + 1 + || curr[-1] != (char)('H' | 0200)) + break; + column -= 2; + if (c == curr[-2]) + goto enter_boldface; + if (c == '_' || curr[-2] == '_') + goto enter_underline; + curr -= 2; + break; + +enter_boldface: + /* + * We have "X\bX" (including the current char). + * Switch into boldface mode. + */ + column--; + if (column + bo_width + be_width + 1 >= sc_width) + /* + * Not enough room left on the screen to + * enter and exit boldface mode. + */ + return (1); + + if (bo_width > 0 && curr > linebuf + 2 + && curr[-3] == ' ') { + /* + * Special case for magic cookie terminals: + * if the previous char was a space, replace + * it with the "enter boldface" sequence. + */ + curr[-3] = BO_CHAR; + column += bo_width-1; + } else { + curr[-1] = curr[-2]; + curr[-2] = BO_CHAR; + column += bo_width; + curr++; + } + goto ln_bo_xb_case; + +enter_underline: + /* + * We have either "_\bX" or "X\b_" (including + * the current char). Switch into underline mode. + */ + column--; + if (column + ul_width + ue_width + 1 >= sc_width) + /* + * Not enough room left on the screen to + * enter and exit underline mode. + */ + return (1); + + if (ul_width > 0 && + curr > linebuf + 2 && curr[-3] == ' ') + { + /* + * Special case for magic cookie terminals: + * if the previous char was a space, replace + * it with the "enter underline" sequence. + */ + curr[-3] = UL_CHAR; + column += ul_width-1; + } else + { + curr[-1] = curr[-2]; + curr[-2] = UL_CHAR; + column += ul_width; + curr++; + } + goto ln_ul_xb_case; + /*NOTREACHED*/ + case LN_UL_XB: + /* + * Termination of a sequence "_\bX" or "X\b_". + */ + if (c != '_' && curr[-2] != '_' && c == curr[-2]) + { + /* + * We seem to have run on from underlining + * into boldfacing - this is a nasty fix, but + * until this whole routine is rewritten as a + * real DFA, ... well ... + */ + curr[0] = curr[-2]; + curr[-2] = UE_CHAR; + curr[-1] = BO_CHAR; + curr += 2; /* char & non-existent backspace */ + ln_state = LN_BO_XB; + goto ln_bo_xb_case; + } +ln_ul_xb_case: + if (c == '_') + c = curr[-2]; + curr -= 2; + ln_state = LN_UNDERLINE; + break; + case LN_BO_XB: + /* + * Termination of a sequnce "X\bX". + */ + if (c != curr[-2] && (c == '_' || curr[-2] == '_')) + { + /* + * We seem to have run on from + * boldfacing into underlining. + */ + curr[0] = curr[-2]; + curr[-2] = BE_CHAR; + curr[-1] = UL_CHAR; + curr += 2; /* char & non-existent backspace */ + ln_state = LN_UL_XB; + goto ln_ul_xb_case; + } +ln_bo_xb_case: + curr -= 2; + ln_state = LN_BOLDFACE; + break; + case LN_UNDERLINE: + if (column + ue_width + bo_width + 1 + be_width >= sc_width) + /* + * We have just barely enough room to + * exit underline mode and handle a possible + * underline/boldface run on mixup. + */ + return (1); + ln_state = LN_UL_X; + break; + case LN_BOLDFACE: + if (c == '\b') + { + ln_state = LN_BO_XB; + break; + } + if (column + be_width + ul_width + 1 + ue_width >= sc_width) + /* + * We have just barely enough room to + * exit underline mode and handle a possible + * underline/boldface run on mixup. + */ + return (1); + ln_state = LN_BO_X; + break; + case LN_UL_X: + if (c == '\b') + ln_state = LN_UL_XB; + else + { + /* + * Exit underline mode. + * We have to shuffle the chars a bit + * to make this work. + */ + curr[0] = curr[-1]; + curr[-1] = UE_CHAR; + column += ue_width; + if (ue_width > 0 && curr[0] == ' ') + /* + * Another special case for magic + * cookie terminals: if the next + * char is a space, replace it + * with the "exit underline" sequence. + */ + column--; + else + curr++; + ln_state = LN_NORMAL; + } + break; + case LN_BO_X: + if (c == '\b') + ln_state = LN_BO_XB; + else + { + /* + * Exit boldface mode. + * We have to shuffle the chars a bit + * to make this work. + */ + curr[0] = curr[-1]; + curr[-1] = BE_CHAR; + column += be_width; + if (be_width > 0 && curr[0] == ' ') + /* + * Another special case for magic + * cookie terminals: if the next + * char is a space, replace it + * with the "exit boldface" sequence. + */ + column--; + else + curr++; + ln_state = LN_NORMAL; + } + break; + } + } + + if (c == '\t') { + /* + * Expand a tab into spaces. + */ + do { + NEW_COLUMN(1); + } while ((column % tabstop) != 0); + *curr++ = '\t'; + return (0); + } + + if (c == '\b') { + if (ln_state == LN_NORMAL) + NEW_COLUMN(2); + else + column--; + *curr++ = ('H' | 0200); + return(0); + } + + if (CONTROL_CHAR(c)) { + /* + * Put a "^X" into the buffer. The 0200 bit is used to tell + * put_line() to prefix the char with a ^. We don't actually + * put the ^ in the buffer because we sometimes need to move + * chars around, and such movement might separate the ^ from + * its following character. + */ + NEW_COLUMN(2); + *curr++ = (CARAT_CHAR(c) | 0200); + return(0); + } + + /* + * Ordinary character. Just put it in the buffer. + */ + NEW_COLUMN(1); + *curr++ = c; + return (0); +} + +/* + * Analogous to forw_line(), but deals with "raw lines": + * lines which are not split for screen width. + * {{ This is supposed to be more efficient than forw_line(). }} + */ +off_t +forw_raw_line(curr_pos) + off_t curr_pos; +{ + register char *p; + register int c; + off_t new_pos, ch_tell(); + + if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || + (c = ch_forw_get()) == EOI) + return (NULL_POSITION); + + p = linebuf; + + for (;;) + { + if (c == '\n' || c == EOI) + { + new_pos = ch_tell(); + break; + } + if (p >= &linebuf[sizeof(linebuf)-1]) + { + /* + * Overflowed the input buffer. + * Pretend the line ended here. + * {{ The line buffer is supposed to be big + * enough that this never happens. }} + */ + new_pos = ch_tell() - 1; + break; + } + *p++ = c; + c = ch_forw_get(); + } + *p = '\0'; + line = linebuf; + return (new_pos); +} + +/* + * Analogous to back_line(), but deals with "raw lines". + * {{ This is supposed to be more efficient than back_line(). }} + */ +off_t +back_raw_line(curr_pos) + off_t curr_pos; +{ + register char *p; + register int c; + off_t new_pos, ch_tell(); + + if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || + ch_seek(curr_pos-1)) + return (NULL_POSITION); + + p = &linebuf[sizeof(linebuf)]; + *--p = '\0'; + + for (;;) + { + c = ch_back_get(); + if (c == '\n') + { + /* + * This is the newline ending the previous line. + * We have hit the beginning of the line. + */ + new_pos = ch_tell() + 1; + break; + } + if (c == EOI) + { + /* + * We have hit the beginning of the file. + * This must be the first line in the file. + * This must, of course, be the beginning of the line. + */ + new_pos = (off_t)0; + break; + } + if (p <= linebuf) + { + /* + * Overflowed the input buffer. + * Pretend the line ended here. + */ + new_pos = ch_tell() + 1; + break; + } + *--p = c; + } + line = p; + return (new_pos); +} diff --git a/usr.bin/more/linenum.c b/usr.bin/more/linenum.c new file mode 100644 index 0000000..4bfefa8 --- /dev/null +++ b/usr.bin/more/linenum.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)linenum.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Code to handle displaying line numbers. + * + * Finding the line number of a given file position is rather tricky. + * We don't want to just start at the beginning of the file and + * count newlines, because that is slow for large files (and also + * wouldn't work if we couldn't get to the start of the file; e.g. + * if input is a long pipe). + * + * So we use the function add_lnum to cache line numbers. + * We try to be very clever and keep only the more interesting + * line numbers when we run out of space in our table. A line + * number is more interesting than another when it is far from + * other line numbers. For example, we'd rather keep lines + * 100,200,300 than 100,101,300. 200 is more interesting than + * 101 because 101 can be derived very cheaply from 100, while + * 200 is more expensive to derive from 100. + * + * The function currline() returns the line number of a given + * position in the file. As a side effect, it calls add_lnum + * to cache the line number. Therefore currline is occasionally + * called to make sure we cache line numbers often enough. + */ + +#include +#include +#include + +/* + * Structure to keep track of a line number and the associated file position. + * A doubly-linked circular list of line numbers is kept ordered by line number. + */ +struct linenum +{ + struct linenum *next; /* Link to next in the list */ + struct linenum *prev; /* Line to previous in the list */ + off_t pos; /* File position */ + off_t gap; /* Gap between prev and next */ + int line; /* Line number */ +}; +/* + * "gap" needs some explanation: the gap of any particular line number + * is the distance between the previous one and the next one in the list. + * ("Distance" means difference in file position.) In other words, the + * gap of a line number is the gap which would be introduced if this + * line number were deleted. It is used to decide which one to replace + * when we have a new one to insert and the table is full. + */ + +#define NPOOL 50 /* Size of line number pool */ + +#define LONGTIME (2) /* In seconds */ + +int lnloop = 0; /* Are we in the line num loop? */ + +static struct linenum anchor; /* Anchor of the list */ +static struct linenum *freelist; /* Anchor of the unused entries */ +static struct linenum pool[NPOOL]; /* The pool itself */ +static struct linenum *spare; /* We always keep one spare entry */ + +extern int linenums; +extern int sigs; + +/* + * Initialize the line number structures. + */ +clr_linenum() +{ + register struct linenum *p; + + /* + * Put all the entries on the free list. + * Leave one for the "spare". + */ + for (p = pool; p < &pool[NPOOL-2]; p++) + p->next = p+1; + pool[NPOOL-2].next = NULL; + freelist = pool; + + spare = &pool[NPOOL-1]; + + /* + * Initialize the anchor. + */ + anchor.next = anchor.prev = &anchor; + anchor.gap = 0; + anchor.pos = (off_t)0; + anchor.line = 1; +} + +/* + * Calculate the gap for an entry. + */ +static +calcgap(p) + register struct linenum *p; +{ + /* + * Don't bother to compute a gap for the anchor. + * Also don't compute a gap for the last one in the list. + * The gap for that last one should be considered infinite, + * but we never look at it anyway. + */ + if (p == &anchor || p->next == &anchor) + return; + p->gap = p->next->pos - p->prev->pos; +} + +/* + * Add a new line number to the cache. + * The specified position (pos) should be the file position of the + * FIRST character in the specified line. + */ +add_lnum(line, pos) + int line; + off_t pos; +{ + register struct linenum *p; + register struct linenum *new; + register struct linenum *nextp; + register struct linenum *prevp; + register off_t mingap; + + /* + * Find the proper place in the list for the new one. + * The entries are sorted by position. + */ + for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) + if (p->line == line) + /* We already have this one. */ + return; + nextp = p; + prevp = p->prev; + + if (freelist != NULL) + { + /* + * We still have free (unused) entries. + * Use one of them. + */ + new = freelist; + freelist = freelist->next; + } else + { + /* + * No free entries. + * Use the "spare" entry. + */ + new = spare; + spare = NULL; + } + + /* + * Fill in the fields of the new entry, + * and insert it into the proper place in the list. + */ + new->next = nextp; + new->prev = prevp; + new->pos = pos; + new->line = line; + + nextp->prev = new; + prevp->next = new; + + /* + * Recalculate gaps for the new entry and the neighboring entries. + */ + calcgap(new); + calcgap(nextp); + calcgap(prevp); + + if (spare == NULL) + { + /* + * We have used the spare entry. + * Scan the list to find the one with the smallest + * gap, take it out and make it the spare. + * We should never remove the last one, so stop when + * we get to p->next == &anchor. This also avoids + * looking at the gap of the last one, which is + * not computed by calcgap. + */ + mingap = anchor.next->gap; + for (p = anchor.next; p->next != &anchor; p = p->next) + { + if (p->gap <= mingap) + { + spare = p; + mingap = p->gap; + } + } + spare->next->prev = spare->prev; + spare->prev->next = spare->next; + } +} + +/* + * If we get stuck in a long loop trying to figure out the + * line number, print a message to tell the user what we're doing. + */ +static +longloopmessage() +{ + ierror("Calculating line numbers"); + /* + * Set the lnloop flag here, so if the user interrupts while + * we are calculating line numbers, the signal handler will + * turn off line numbers (linenums=0). + */ + lnloop = 1; +} + +/* + * Find the line number associated with a given position. + * Return 0 if we can't figure it out. + */ +find_linenum(pos) + off_t pos; +{ + register struct linenum *p; + register int lno; + register int loopcount; + off_t cpos, back_raw_line(), forw_raw_line(); + time_t startime, time(); + + if (!linenums) + /* + * We're not using line numbers. + */ + return (0); + if (pos == NULL_POSITION) + /* + * Caller doesn't know what he's talking about. + */ + return (0); + if (pos == (off_t)0) + /* + * Beginning of file is always line number 1. + */ + return (1); + + /* + * Find the entry nearest to the position we want. + */ + for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) + continue; + if (p->pos == pos) + /* Found it exactly. */ + return (p->line); + + /* + * This is the (possibly) time-consuming part. + * We start at the line we just found and start + * reading the file forward or backward till we + * get to the place we want. + * + * First decide whether we should go forward from the + * previous one or backwards from the next one. + * The decision is based on which way involves + * traversing fewer bytes in the file. + */ + flush(); + (void)time(&startime); + if (p == &anchor || pos - p->prev->pos < p->pos - pos) + { + /* + * Go forward. + */ + p = p->prev; + if (ch_seek(p->pos)) + return (0); + loopcount = 0; + for (lno = p->line, cpos = p->pos; cpos < pos; lno++) + { + /* + * Allow a signal to abort this loop. + */ + cpos = forw_raw_line(cpos); + if (sigs || cpos == NULL_POSITION) + return (0); + if (loopcount >= 0 && ++loopcount > 100) { + loopcount = 0; + if (time((time_t *)NULL) + >= startime + LONGTIME) { + longloopmessage(); + loopcount = -1; + } + } + } + lnloop = 0; + /* + * If the given position is not at the start of a line, + * make sure we return the correct line number. + */ + if (cpos > pos) + lno--; + } else + { + /* + * Go backward. + */ + if (ch_seek(p->pos)) + return (0); + loopcount = 0; + for (lno = p->line, cpos = p->pos; cpos > pos; lno--) + { + /* + * Allow a signal to abort this loop. + */ + cpos = back_raw_line(cpos); + if (sigs || cpos == NULL_POSITION) + return (0); + if (loopcount >= 0 && ++loopcount > 100) { + loopcount = 0; + if (time((time_t *)NULL) + >= startime + LONGTIME) { + longloopmessage(); + loopcount = -1; + } + } + } + lnloop = 0; + } + + /* + * We might as well cache it. + */ + add_lnum(lno, cpos); + return (lno); +} + +/* + * Return the line number of the "current" line. + * The argument "where" tells which line is to be considered + * the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc). + */ +currline(where) + int where; +{ + off_t pos, ch_length(), position(); + + if ((pos = position(where)) == NULL_POSITION) + pos = ch_length(); + return(find_linenum(pos)); +} diff --git a/usr.bin/more/main.c b/usr.bin/more/main.c new file mode 100644 index 0000000..f019bdc --- /dev/null +++ b/usr.bin/more/main.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1988 Mark Nudleman.\n\ +@(#) Copyright (c) 1988, 1993 + Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/7/93"; +#endif /* not lint */ + +/* + * Entry point, initialization, miscellaneous routines. + */ + +#include +#include +#include +#include + +int ispipe; +int new_file; +int is_tty; +char *current_file, *previous_file, *current_name, *next_name; +off_t prev_pos; +int any_display; +int scroll; +int ac; +char **av; +int curr_ac; +int quitting; + +extern int file; +extern int cbufs; +extern int errmsgs; + +extern char *tagfile; +extern int tagoption; + +/* + * Edit a new file. + * Filename "-" means standard input. + * No filename means the "current" file, from the command line. + */ +edit(filename) + register char *filename; +{ + extern int errno; + register int f; + register char *m; + off_t initial_pos, position(); + static int didpipe; + char message[100], *p; + char *rindex(), *strerror(), *save(), *bad_file(); + + initial_pos = NULL_POSITION; + if (filename == NULL || *filename == '\0') { + if (curr_ac >= ac) { + error("No current file"); + return(0); + } + filename = save(av[curr_ac]); + } + else if (strcmp(filename, "#") == 0) { + if (*previous_file == '\0') { + error("no previous file"); + return(0); + } + filename = save(previous_file); + initial_pos = prev_pos; + } else + filename = save(filename); + + /* use standard input. */ + if (!strcmp(filename, "-")) { + if (didpipe) { + error("Can view standard input only once"); + return(0); + } + f = 0; + } + else if ((m = bad_file(filename, message, sizeof(message))) != NULL) { + error(m); + free(filename); + return(0); + } + else if ((f = open(filename, O_RDONLY, 0)) < 0) { + (void)sprintf(message, "%s: %s", filename, strerror(errno)); + error(message); + free(filename); + return(0); + } + + if (isatty(f)) { + /* + * Not really necessary to call this an error, + * but if the control terminal (for commands) + * and the input file (for data) are the same, + * we get weird results at best. + */ + error("Can't take input from a terminal"); + if (f > 0) + (void)close(f); + (void)free(filename); + return(0); + } + + /* + * We are now committed to using the new file. + * Close the current input file and set up to use the new one. + */ + if (file > 0) + (void)close(file); + new_file = 1; + if (previous_file != NULL) + free(previous_file); + previous_file = current_file; + current_file = filename; + pos_clear(); + prev_pos = position(TOP); + ispipe = (f == 0); + if (ispipe) { + didpipe = 1; + current_name = "stdin"; + } else + current_name = (p = rindex(filename, '/')) ? p + 1 : filename; + if (curr_ac >= ac) + next_name = NULL; + else + next_name = av[curr_ac + 1]; + file = f; + ch_init(cbufs, 0); + init_mark(); + + if (is_tty) { + int no_display = !any_display; + any_display = 1; + if (no_display && errmsgs > 0) { + /* + * We displayed some messages on error output + * (file descriptor 2; see error() function). + * Before erasing the screen contents, + * display the file name and wait for a keystroke. + */ + error(filename); + } + /* + * Indicate there is nothing displayed yet. + */ + if (initial_pos != NULL_POSITION) + jump_loc(initial_pos); + clr_linenum(); + } + return(1); +} + +/* + * Edit the next file in the command line list. + */ +next_file(n) + int n; +{ + extern int quit_at_eof; + off_t position(); + + if (curr_ac + n >= ac) { + if (quit_at_eof || position(TOP) == NULL_POSITION) + quit(); + error("No (N-th) next file"); + } + else + (void)edit(av[curr_ac += n]); +} + +/* + * Edit the previous file in the command line list. + */ +prev_file(n) + int n; +{ + if (curr_ac - n < 0) + error("No (N-th) previous file"); + else + (void)edit(av[curr_ac -= n]); +} + +/* + * copy a file directly to standard output; used if stdout is not a tty. + * the only processing is to squeeze multiple blank input lines. + */ +static +cat_file() +{ + extern int squeeze; + register int c, empty; + + if (squeeze) { + empty = 0; + while ((c = ch_forw_get()) != EOI) + if (c != '\n') { + putchr(c); + empty = 0; + } + else if (empty < 2) { + putchr(c); + ++empty; + } + } + else while ((c = ch_forw_get()) != EOI) + putchr(c); + flush(); +} + +main(argc, argv) + int argc; + char **argv; +{ + int envargc, argcnt; + char *envargv[2], *getenv(); + + /* + * Process command line arguments and MORE environment arguments. + * Command line arguments override environment arguments. + */ + if (envargv[1] = getenv("MORE")) { + envargc = 2; + envargv[0] = "more"; + envargv[2] = NULL; + (void)option(envargc, envargv); + } + argcnt = option(argc, argv); + argv += argcnt; + argc -= argcnt; + + /* + * Set up list of files to be examined. + */ + ac = argc; + av = argv; + curr_ac = 0; + + /* + * Set up terminal, etc. + */ + is_tty = isatty(1); + if (!is_tty) { + /* + * Output is not a tty. + * Just copy the input file(s) to output. + */ + if (ac < 1) { + (void)edit("-"); + cat_file(); + } else { + do { + (void)edit((char *)NULL); + if (file >= 0) + cat_file(); + } while (++curr_ac < ac); + } + exit(0); + } + + raw_mode(1); + get_term(); + open_getchr(); + init(); + init_signals(1); + + /* select the first file to examine. */ + if (tagoption) { + /* + * A -t option was given; edit the file selected by the + * "tags" search, and search for the proper line in the file. + */ + if (!tagfile || !edit(tagfile) || tagsearch()) + quit(); + } + else if (ac < 1) + (void)edit("-"); /* Standard input */ + else { + /* + * Try all the files named as command arguments. + * We are simply looking for one which can be + * opened without error. + */ + do { + (void)edit((char *)NULL); + } while (file < 0 && ++curr_ac < ac); + } + + if (file >= 0) + commands(); + quit(); + /*NOTREACHED*/ +} + +/* + * Copy a string to a "safe" place + * (that is, to a buffer allocated by malloc). + */ +char * +save(s) + char *s; +{ + char *p, *strcpy(), *malloc(); + + p = malloc((u_int)strlen(s)+1); + if (p == NULL) + { + error("cannot allocate memory"); + quit(); + } + return(strcpy(p, s)); +} + +/* + * Exit the program. + */ +quit() +{ + /* + * Put cursor at bottom left corner, clear the line, + * reset the terminal modes, and exit. + */ + quitting = 1; + lower_left(); + clear_eol(); + deinit(); + flush(); + raw_mode(0); + exit(0); +} diff --git a/usr.bin/more/more.1 b/usr.bin/more/more.1 new file mode 100644 index 0000000..209b617 --- /dev/null +++ b/usr.bin/more/more.1 @@ -0,0 +1,298 @@ +.\" Copyright (c) 1988, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)more.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt MORE 1 +.Os +.Sh NAME +.Nm more +.Nd file perusal filter for crt viewing +.Sh SYNOPSIS +.Nm more +.Op Fl ceinus +.Op Fl t Ar tag +.Op Fl x Ar tabs +.Op Fl / Ar pattern +.Op Fl # +.Op Ar +.Sh DESCRIPTION +.Nm More +is a filter for paging through text one screenful at a time. It +uses +.Xr termcap 3 +so it can run on a variety of terminals. There is even limited support +for hardcopy terminals. (On a hardcopy terminal, lines which should be +printed at the top of the screen are prefixed with an up-arrow.) +.Ar File +may be a single dash (``-''), implying stdin. +.Sh OPTIONS +Command line options are described below. +Options are also taken from the environment variable +.Ev MORE +(make sure to precede them with a dash (``-'')) but command +line options will override them. +.Bl -tag -width flag +.It Fl c +Normally, +.Nm more +will repaint the screen by scrolling from the bottom of the screen. +If the +.Fl c +option is set, when +.Nm more +needs to change the entire display, it will paint from the top line down. +.It Fl e +Normally, if displaying a single file, +.Nm more +exits as soon as it reaches end-of-file. The +.Fl e +option tells more to +exit if it reaches end-of-file twice without an intervening operation. +If the file is shorter than a single screen +.Nm more +will exit at end-of-file regardless. +.It Fl i +The +.Fl i +option causes searches to ignore case; that is, +uppercase and lowercase are considered identical. +.It Fl n +The +.Fl n +flag suppresses line numbers. +The default (to use line numbers) may cause +.Nm more +to run more slowly in some cases, especially with a very large input file. +Suppressing line numbers with the +.Fl n +flag will avoid this problem. +Using line numbers means: the line number will be displayed in the +.Cm = +command, and the +.Cm v +command will pass the current line number to the editor. +.It Fl s +The +.Fl s +option causes +consecutive blank lines to be squeezed into a single blank line. +.It Fl t +The +.Fl t +option, followed immediately by a tag, will edit the file +containing that tag. For more information, see the +.Xr ctags 1 +command. +.It Fl u +By default, +.Nm more +treats backspaces and +.Dv CR-LF +sequences specially. Backspaces which appear +adjacent to an underscore character are displayed as underlined text. +Backspaces which appear between two identical characters are displayed +as emboldened text. +.Dv CR-LF +sequences are compressed to a single linefeed +character. The +.Fl u +option causes backspaces to always be displayed as +control characters, i.e. as the two character sequence ``^H'', and +.Dv CR-LF +to be left alone. +.It Fl x +The +.Fl x +option sets tab stops every +.Ar N +positions. The default for +.Ar N +is 8. +.It Fl / +The +.Fl / +option specifies a string that will be searched for before +each file is displayed. +.Sh COMMANDS +Interactive commands for +.Nm more +are based on +.Xr vi 1 . +Some commands may be preceded by a decimal number, called N in the +descriptions below. +In the following descriptions, ^X means control-X. +.Pp +.Bl -tag -width Ic +.It Ic h +Help: display a summary of these commands. +If you forget all the other commands, remember this one. +.It Xo +.Ic SPACE +.No or +.Ic f +.No or +.Ic \&^F +.Xc +Scroll forward N lines, default one window. +If N is more than the screen size, only the final screenful is displayed. +.It Ic b No or Ic \&^B +Scroll backward N lines, default one window (see option -z below). +If N is more than the screen size, only the final screenful is displayed. +.It Ic j No or Ic RETURN +Scroll forward N lines, default 1. +The entire N lines are displayed, even if N is more than the screen size. +.It Ic k +Scroll backward N lines, default 1. +The entire N lines are displayed, even if N is more than the screen size. +.It Ic d No or Ic \&^D +Scroll forward N lines, default one half of the screen size. +If N is specified, it becomes the new default for +subsequent d and u commands. +.It Ic u No or Ic \&^U +Scroll backward N lines, default one half of the screen size. +If N is specified, it becomes the new default for +subsequent d and u commands. +.It Ic g +Go to line N in the file, default 1 (beginning of file). +.It Ic G +Go to line N in the file, default the end of the file. +.It Ic p No or Ic \&% +Go to a position N percent into the file. N should be between 0 +and 100. (This works if standard input is being read, but only if +.Nm more +has already read to the end of the file. It is always fast, but +not always useful.) +.It Ic r No or Ic \&^L +Repaint the screen. +.It Ic R +Repaint the screen, discarding any buffered input. +Useful if the file is changing while it is being viewed. +.It Ic m +Followed by any lowercase letter, +marks the current position with that letter. +.It Ic \&' +(Single quote.) +Followed by any lowercase letter, returns to the position which +was previously marked with that letter. +Followed by another single quote, returns to the position at +which the last "large" movement command was executed, or the +beginning of the file if no such movements have occurred. +All marks are lost when a new file is examined. +.It Ic \&/ Ns Ar pattern +Search forward in the file for the N-th line containing the pattern. +N defaults to 1. +The pattern is a regular expression, as recognized by +.Xr ed . +The search starts at the second line displayed. +.It Ic \&? Ns Ar pattern +Search backward in the file for the N-th line containing the pattern. +The search starts at the line immediately before the top line displayed. +.It Ic \&/\&! Ns Ar pattern +Like /, but the search is for the N-th line +which does NOT contain the pattern. +.It Ic \&?\&! Ns Ar pattern +Like ?, but the search is for the N-th line +which does NOT contain the pattern. +.It Ic n +Repeat previous search, for N-th line containing the last pattern +(or +.Tn NOT +containing the last pattern, if the previous search +was /! or ?!). +.It Ic E Ns Op Ar filename +Examine a new file. +If the filename is missing, the "current" file (see the N and P commands +below) from the list of files in the command line is re-examined. +If the filename is a pound sign (#), the previously examined file is +re-examined. +.It Ic N No or Ic \&:n +Examine the next file (from the list of files given in the command line). +If a number N is specified (not to be confused with the command N), +the N-th next file is examined. +.It Ic P No or Ic \&:p +Examine the previous file. +If a number N is specified, the N-th previous file is examined. +.It Ic \&:t +Go to supplied tag. +.It Ic v +Invokes an editor to edit the current file being viewed. +The editor is taken from the environment variable +.Ev EDITOR , +or defaults to +.Xr vi 1 . +.It Ic \&= No or Ic \&^G +These options print out the number of the file currently being displayed +relative to the total number of files there are to display, the current +line number, the current byte number and the total bytes to display, and +what percentage of the file has been displayed. If +.Nm more +is reading from stdin, or the file is shorter than a single screen, some +of these items may not be available. Note, all of these items reference +the first byte of the last line displayed on the screen. +.It Xo +.Ic q +.No or +.Ic \&:q +.No or +.Ic ZZ +.Xc +Exits +.Nm more . +.El +.Sh ENVIRONMENT +.Nm More +utilizes the following environment variables, if they exist: +.Bl -tag -width Fl +.It Ev MORE +This variable may be set with favored options to +.Nm more . +.It Ev EDITOR +Specify default editor. +.It Ev SHELL +Current shell in use (normally set by the shell at login time). +.It Ev TERM +Specifies terminal type, used by more to get the terminal +characteristics necessary to manipulate the screen. +.El +.Sh SEE ALSO +.Xr ctags 1 , +.Xr vi 1 +.Sh AUTHOR +This software is derived from software contributed to Berkeley +by Mark Nudleman. +.Sh HISTORY +The +.Nm more +command appeared in +.Bx 3.0 . diff --git a/usr.bin/more/more.help b/usr.bin/more/more.help new file mode 100644 index 0000000..fcef82f --- /dev/null +++ b/usr.bin/more/more.help @@ -0,0 +1,39 @@ + Commands flagged with an asterisk (``*'') may be preceeded by a number. + Commands of the form ``^X'' are control characters, i.e. control-X. + + h Display this help. + + f, ^F, SPACE * Forward N lines, default one screen. + b, ^B * Backward N lines, default one screen. + j, CR * Forward N lines, default 1 line. + k * Backward N lines, default 1 line. + d, ^D * Forward N lines, default half screen or last N to d/u. + u, ^U * Backward N lines, default half screen or last N to d/u. + g * Go to line N, default 1. + G * Go to line N, default the end of the file. + p, % * Position to N percent into the file. + + r, ^L Repaint screen. + R Repaint screen, discarding buffered input. + + m[a-z] Mark the current position with the supplied letter. + '[a-z] Return to the position previously marked by this letter. + '' Return to previous position. + + /pattern * Search forward for N-th line containing the pattern. + /!pattern * Search forward for N-th line NOT containing the pattern. + ?pattern * Search backward for N-th line containing the pattern. + ?!pattern * Search backward for N-th line NOT containing the pattern. + n * Repeat previous search (for N-th occurence). + + :a Display the list of files. + E [file] Examine a new file. + :n, N * Examine the next file. + :p, P * Examine the previous file. + :t [tag] Examine the tag. + v Run an editor on the current file. + + =, ^G Print current file name and stats. + + q, :q, or ZZ Exit. + diff --git a/usr.bin/more/option.c b/usr.bin/more/option.c new file mode 100644 index 0000000..29349d0 --- /dev/null +++ b/usr.bin/more/option.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)option.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +int top_scroll; /* Repaint screen from top */ +int bs_mode; /* How to process backspaces */ +int caseless; /* Do "caseless" searches */ +int cbufs = 10; /* Current number of buffers */ +int linenums = 1; /* Use line numbers */ +int quit_at_eof; +int squeeze; /* Squeeze multiple blank lines into one */ +int tabstop = 8; /* Tab settings */ +int tagoption; + +char *firstsearch; +extern int sc_height; + +option(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + static int sc_window_set = 0; + int ch; + char *p; + + /* backward compatible processing for "+/search" */ + char **a; + for (a = argv; *a; ++a) + if ((*a)[0] == '+' && (*a)[1] == '/') + (*a)[0] = '-'; + + optind = 1; /* called twice, re-init getopt. */ + while ((ch = getopt(argc, argv, "0123456789/:ceinst:ux:f")) != EOF) + switch((char)ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: more was originally designed to take + * a number after a dash. + */ + if (!sc_window_set) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + sc_height = atoi(++p); + else + sc_height = atoi(argv[optind] + 1); + sc_window_set = 1; + } + break; + case '/': + firstsearch = optarg; + break; + case 'c': + top_scroll = 1; + break; + case 'e': + quit_at_eof = 1; + break; + case 'i': + caseless = 1; + break; + case 'n': + linenums = 0; + break; + case 's': + squeeze = 1; + break; + case 't': + tagoption = 1; + findtag(optarg); + break; + case 'u': + bs_mode = 1; + break; + case 'x': + tabstop = atoi(optarg); + if (tabstop <= 0) + tabstop = 8; + break; + case 'f': /* ignore -f, compatability with old more */ + break; + case '?': + default: + fprintf(stderr, + "usage: more [-ceinus] [-t tag] [-x tabs] [-/ pattern] [-#] [file ...]\n"); + exit(1); + } + return(optind); +} diff --git a/usr.bin/more/os.c b/usr.bin/more/os.c new file mode 100644 index 0000000..75b7a6e --- /dev/null +++ b/usr.bin/more/os.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)os.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Operating system dependent routines. + * + * Most of the stuff in here is based on Unix, but an attempt + * has been made to make things work on other operating systems. + * This will sometimes result in a loss of functionality, unless + * someone rewrites code specifically for the new operating system. + * + * The makefile provides defines to decide whether various + * Unix features are present. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +int reading; + +extern int screen_trashed; + +static jmp_buf read_label; + +/* + * Pass the specified command to a shell to be executed. + * Like plain "system()", but handles resetting terminal modes, etc. + */ +lsystem(cmd) + char *cmd; +{ + int inp; + char cmdbuf[256]; + char *shell, *getenv(); + + /* + * Print the command which is to be executed, + * unless the command starts with a "-". + */ + if (cmd[0] == '-') + cmd++; + else + { + lower_left(); + clear_eol(); + putstr("!"); + putstr(cmd); + putstr("\n"); + } + + /* + * De-initialize the terminal and take out of raw mode. + */ + deinit(); + flush(); + raw_mode(0); + + /* + * Restore signals to their defaults. + */ + init_signals(0); + + /* + * Force standard input to be the terminal, "/dev/tty", + * even if less's standard input is coming from a pipe. + */ + inp = dup(0); + (void)close(0); + if (open(_PATH_TTY, O_RDONLY, 0) < 0) + (void)dup(inp); + + /* + * Pass the command to the system to be executed. + * If we have a SHELL environment variable, use + * <$SHELL -c "command"> instead of just . + * If the command is empty, just invoke a shell. + */ + if ((shell = getenv("SHELL")) != NULL && *shell != '\0') + { + if (*cmd == '\0') + cmd = shell; + else + { + (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd); + cmd = cmdbuf; + } + } + if (*cmd == '\0') + cmd = "sh"; + + (void)system(cmd); + + /* + * Restore standard input, reset signals, raw mode, etc. + */ + (void)close(0); + (void)dup(inp); + (void)close(inp); + + init_signals(1); + raw_mode(1); + init(); + screen_trashed = 1; +#if defined(SIGWINCH) || defined(SIGWIND) + /* + * Since we were ignoring window change signals while we executed + * the system command, we must assume the window changed. + */ + winch(); +#endif +} + +/* + * Like read() system call, but is deliberately interruptable. + * A call to intread() from a signal handler will interrupt + * any pending iread(). + */ +iread(fd, buf, len) + int fd; + char *buf; + int len; +{ + register int n; + + if (setjmp(read_label)) + /* + * We jumped here from intread. + */ + return (READ_INTR); + + flush(); + reading = 1; + n = read(fd, buf, len); + reading = 0; + if (n < 0) + return (-1); + return (n); +} + +intread() +{ + (void)sigsetmask(0L); + longjmp(read_label, 1); +} + +/* + * Expand a filename, substituting any environment variables, etc. + * The implementation of this is necessarily very operating system + * dependent. This implementation is unabashedly only for Unix systems. + */ +FILE *popen(); + +char * +glob(filename) + char *filename; +{ + FILE *f; + char *p; + int ch; + char *cmd, *malloc(), *getenv(); + static char buffer[MAXPATHLEN]; + + if (filename[0] == '#') + return (filename); + + /* + * We get the shell to expand the filename for us by passing + * an "echo" command to the shell and reading its output. + */ + p = getenv("SHELL"); + if (p == NULL || *p == '\0') + { + /* + * Read the output of . + */ + cmd = malloc((u_int)(strlen(filename)+8)); + if (cmd == NULL) + return (filename); + (void)sprintf(cmd, "echo \"%s\"", filename); + } else + { + /* + * Read the output of <$SHELL -c "echo filename">. + */ + cmd = malloc((u_int)(strlen(p)+12)); + if (cmd == NULL) + return (filename); + (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename); + } + + if ((f = popen(cmd, "r")) == NULL) + return (filename); + free(cmd); + + for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++) + { + if ((ch = getc(f)) == '\n' || ch == EOF) + break; + *p = ch; + } + *p = '\0'; + (void)pclose(f); + return(buffer); +} + +char * +bad_file(filename, message, len) + char *filename, *message; + u_int len; +{ + extern int errno; + struct stat statbuf; + char *strcat(), *strerror(); + + if (stat(filename, &statbuf) < 0) { + (void)sprintf(message, "%s: %s", filename, strerror(errno)); + return(message); + } + if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { + static char is_dir[] = " is a directory"; + + strtcpy(message, filename, (int)(len-sizeof(is_dir)-1)); + (void)strcat(message, is_dir); + return(message); + } + return((char *)NULL); +} + +/* + * Copy a string, truncating to the specified length if necessary. + * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. + */ +strtcpy(to, from, len) + char *to, *from; + int len; +{ + char *strncpy(); + + (void)strncpy(to, from, (int)len); + to[len-1] = '\0'; +} + diff --git a/usr.bin/more/output.c b/usr.bin/more/output.c new file mode 100644 index 0000000..c721f4e --- /dev/null +++ b/usr.bin/more/output.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)output.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * High level routines dealing with the output to the screen. + */ + +#include +#include + +int errmsgs; /* Count of messages displayed by error() */ + +extern int sigs; +extern int sc_width, sc_height; +extern int ul_width, ue_width; +extern int so_width, se_width; +extern int bo_width, be_width; +extern int tabstop; +extern int screen_trashed; +extern int any_display; +extern char *line; + +/* display the line which is in the line buffer. */ +put_line() +{ + register char *p; + register int c; + register int column; + extern int auto_wrap, ignaw; + + if (sigs) + { + /* + * Don't output if a signal is pending. + */ + screen_trashed = 1; + return; + } + + if (line == NULL) + line = ""; + + column = 0; + for (p = line; *p != '\0'; p++) + { + switch (c = *p) + { + case UL_CHAR: + ul_enter(); + column += ul_width +1; + break; + case UE_CHAR: + ul_exit(); + column += ue_width; + break; + case BO_CHAR: + bo_enter(); + column += bo_width +1; + break; + case BE_CHAR: + bo_exit(); + column += be_width; + break; + case '\t': + do + { + putchr(' '); + column++; + } while ((column % tabstop) != 0); + break; + case '\b': + putbs(); + column--; + break; + default: + if (c & 0200) + { + /* + * Control characters arrive here as the + * normal character [CARAT_CHAR(c)] with + * the 0200 bit set. See pappend(). + */ + putchr('^'); + putchr(c & 0177); + column += 2; + } else + { + putchr(c); + column++; + } + } + } + if (column < sc_width || !auto_wrap || ignaw) + putchr('\n'); +} + +static char obuf[1024]; +static char *ob = obuf; + +/* + * Flush buffered output. + */ +flush() +{ + register int n; + + n = ob - obuf; + if (n == 0) + return; + if (write(1, obuf, n) != n) + screen_trashed = 1; + ob = obuf; +} + +/* + * Purge any pending output. + */ +purge() +{ + + ob = obuf; +} + +/* + * Output a character. + */ +putchr(c) + int c; +{ + if (ob >= &obuf[sizeof(obuf)]) + flush(); + *ob++ = c; +} + +/* + * Output a string. + */ +putstr(s) + register char *s; +{ + while (*s != '\0') + putchr(*s++); +} + +int cmdstack; +static char return_to_continue[] = "(press RETURN)"; + +/* + * Output a message in the lower left corner of the screen + * and wait for carriage return. + */ +error(s) + char *s; +{ + int ch; + + ++errmsgs; + if (!any_display) { + /* + * Nothing has been displayed yet. Output this message on + * error output (file descriptor 2) and don't wait for a + * keystroke to continue. + * + * This has the desirable effect of producing all error + * messages on error output if standard output is directed + * to a file. It also does the same if we never produce + * any real output; for example, if the input file(s) cannot + * be opened. If we do eventually produce output, code in + * edit() makes sure these messages can be seen before they + * are overwritten or scrolled away. + */ + (void)write(2, s, strlen(s)); + (void)write(2, "\n", 1); + return; + } + + lower_left(); + clear_eol(); + so_enter(); + if (s) { + putstr(s); + putstr(" "); + } + putstr(return_to_continue); + so_exit(); + + if ((ch = getchr()) != '\n') { + if (ch == 'q') + quit(); + cmdstack = ch; + } + lower_left(); + + if (strlen(s) + sizeof(return_to_continue) + + so_width + se_width + 1 > sc_width) + /* + * Printing the message has probably scrolled the screen. + * {{ Unless the terminal doesn't have auto margins, + * in which case we just hammered on the right margin. }} + */ + repaint(); + flush(); +} + +static char intr_to_abort[] = "... (interrupt to abort)"; + +ierror(s) + char *s; +{ + lower_left(); + clear_eol(); + so_enter(); + putstr(s); + putstr(intr_to_abort); + so_exit(); + flush(); +} diff --git a/usr.bin/more/pathnames.h b/usr.bin/more/pathnames.h new file mode 100644 index 0000000..c564360 --- /dev/null +++ b/usr.bin/more/pathnames.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_HELPFILE "/usr/share/misc/more.help" diff --git a/usr.bin/more/position.c b/usr.bin/more/position.c new file mode 100644 index 0000000..8564be0 --- /dev/null +++ b/usr.bin/more/position.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)position.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines dealing with the "position" table. + * This is a table which tells the position (in the input file) of the + * first char on each currently displayed line. + * + * {{ The position table is scrolled by moving all the entries. + * Would be better to have a circular table + * and just change a couple of pointers. }} + */ + +#include +#include + +static off_t *table; /* The position table */ +static int tablesize; + +extern int sc_height; + +/* + * Return the starting file position of a line displayed on the screen. + * The line may be specified as a line number relative to the top + * of the screen, but is usually one of these special cases: + * the top (first) line on the screen + * the second line on the screen + * the bottom line on the screen + * the line after the bottom line on the screen + */ +off_t +position(where) + int where; +{ + switch (where) + { + case BOTTOM: + where = sc_height - 2; + break; + case BOTTOM_PLUS_ONE: + where = sc_height - 1; + break; + case MIDDLE: + where = sc_height / 2; + } + return (table[where]); +} + +/* + * Add a new file position to the bottom of the position table. + */ +add_forw_pos(pos) + off_t pos; +{ + register int i; + + /* + * Scroll the position table up. + */ + for (i = 1; i < sc_height; i++) + table[i-1] = table[i]; + table[sc_height - 1] = pos; +} + +/* + * Add a new file position to the top of the position table. + */ +add_back_pos(pos) + off_t pos; +{ + register int i; + + /* + * Scroll the position table down. + */ + for (i = sc_height - 1; i > 0; i--) + table[i] = table[i-1]; + table[0] = pos; +} + +copytable() +{ + register int a, b; + + for (a = 0; a < sc_height && table[a] == NULL_POSITION; a++); + for (b = 0; a < sc_height; a++, b++) { + table[b] = table[a]; + table[a] = NULL_POSITION; + } +} + +/* + * Initialize the position table, done whenever we clear the screen. + */ +pos_clear() +{ + register int i; + extern char *malloc(), *realloc(); + + if (table == 0) { + tablesize = sc_height > 25 ? sc_height : 25; + table = (off_t *)malloc(tablesize * sizeof *table); + } else if (sc_height >= tablesize) { + tablesize = sc_height; + table = (off_t *)realloc(table, tablesize * sizeof *table); + } + + for (i = 0; i < sc_height; i++) + table[i] = NULL_POSITION; +} + +/* + * See if the byte at a specified position is currently on the screen. + * Check the position table to see if the position falls within its range. + * Return the position table entry if found, -1 if not. + */ +onscreen(pos) + off_t pos; +{ + register int i; + + if (pos < table[0]) + return (-1); + for (i = 1; i < sc_height; i++) + if (pos < table[i]) + return (i-1); + return (-1); +} diff --git a/usr.bin/more/prim.c b/usr.bin/more/prim.c new file mode 100644 index 0000000..d5af8f3 --- /dev/null +++ b/usr.bin/more/prim.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)prim.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Primitives for displaying the file on the screen. + */ + +#include +#include +#include +#include + +int back_scroll = -1; +int hit_eof; /* keeps track of how many times we hit end of file */ +int screen_trashed; + +static int squished; + +extern int sigs; +extern int top_scroll; +extern int sc_width, sc_height; +extern int caseless; +extern int linenums; +extern int tagoption; +extern char *line; +extern int retain_below; + +off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line(); +off_t ch_length(), ch_tell(); + +/* + * Check to see if the end of file is currently "displayed". + */ +eof_check() +{ + off_t pos; + + if (sigs) + return; + /* + * If the bottom line is empty, we are at EOF. + * If the bottom line ends at the file length, + * we must be just at EOF. + */ + pos = position(BOTTOM_PLUS_ONE); + if (pos == NULL_POSITION || pos == ch_length()) + hit_eof++; +} + +/* + * If the screen is "squished", repaint it. + * "Squished" means the first displayed line is not at the top + * of the screen; this can happen when we display a short file + * for the first time. + */ +squish_check() +{ + if (squished) { + squished = 0; + repaint(); + } +} + +/* + * Display n lines, scrolling forward, starting at position pos in the + * input file. "only_last" means display only the last screenful if + * n > screen size. + */ +forw(n, pos, only_last) + register int n; + off_t pos; + int only_last; +{ + extern int short_file; + static int first_time = 1; + int eof = 0, do_repaint; + + squish_check(); + + /* + * do_repaint tells us not to display anything till the end, + * then just repaint the entire screen. + */ + do_repaint = (only_last && n > sc_height-1); + + if (!do_repaint) { + if (top_scroll && n >= sc_height - 1) { + /* + * Start a new screen. + * {{ This is not really desirable if we happen + * to hit eof in the middle of this screen, + * but we don't yet know if that will happen. }} + */ + clear(); + home(); + } else { + lower_left(); + clear_eol(); + } + + /* + * This is not contiguous with what is currently displayed. + * Clear the screen image (position table) and start a new + * screen. + */ + if (pos != position(BOTTOM_PLUS_ONE)) { + pos_clear(); + add_forw_pos(pos); + if (top_scroll) { + clear(); + home(); + } else if (!first_time) + putstr("...skipping...\n"); + } + } + + for (short_file = 0; --n >= 0;) { + /* + * Read the next line of input. + */ + pos = forw_line(pos); + if (pos == NULL_POSITION) { + /* + * end of file; copy the table if the file was + * too small for an entire screen. + */ + eof = 1; + if (position(TOP) == NULL_POSITION) { + copytable(); + if (!position(TOP)) + short_file = 1; + } + break; + } + /* + * Add the position of the next line to the position table. + * Display the current line on the screen. + */ + add_forw_pos(pos); + if (do_repaint) + continue; + /* + * If this is the first screen displayed and we hit an early + * EOF (i.e. before the requested number of lines), we + * "squish" the display down at the bottom of the screen. + * But don't do this if a -t option was given; it can cause + * us to start the display after the beginning of the file, + * and it is not appropriate to squish in that case. + */ + if (first_time && line == NULL && !top_scroll && !tagoption) { + squished = 1; + continue; + } + put_line(); + } + + if (eof && !sigs) + hit_eof++; + else + eof_check(); + if (do_repaint) + repaint(); + first_time = 0; + (void) currline(BOTTOM); +} + +/* + * Display n lines, scrolling backward. + */ +back(n, pos, only_last) + register int n; + off_t pos; + int only_last; +{ + int do_repaint; + + squish_check(); + do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); + hit_eof = 0; + while (--n >= 0) + { + /* + * Get the previous line of input. + */ + pos = back_line(pos); + if (pos == NULL_POSITION) + break; + /* + * Add the position of the previous line to the position table. + * Display the line on the screen. + */ + add_back_pos(pos); + if (!do_repaint) + { + if (retain_below) + { + lower_left(); + clear_eol(); + } + home(); + add_line(); + put_line(); + } + } + + eof_check(); + if (do_repaint) + repaint(); + (void) currline(BOTTOM); +} + +/* + * Display n more lines, forward. + * Start just after the line currently displayed at the bottom of the screen. + */ +forward(n, only_last) + int n; + int only_last; +{ + off_t pos; + + if (hit_eof) { + /* + * If we're trying to go forward from end-of-file, + * go on to the next file. + */ + next_file(1); + return; + } + + pos = position(BOTTOM_PLUS_ONE); + if (pos == NULL_POSITION) + { + hit_eof++; + return; + } + forw(n, pos, only_last); +} + +/* + * Display n more lines, backward. + * Start just before the line currently displayed at the top of the screen. + */ +backward(n, only_last) + int n; + int only_last; +{ + off_t pos; + + pos = position(TOP); + /* + * This will almost never happen, because the top line is almost + * never empty. + */ + if (pos == NULL_POSITION) + return; + back(n, pos, only_last); +} + +/* + * Repaint the screen, starting from a specified position. + */ +prepaint(pos) + off_t pos; +{ + hit_eof = 0; + forw(sc_height-1, pos, 0); + screen_trashed = 0; +} + +/* + * Repaint the screen. + */ +repaint() +{ + /* + * Start at the line currently at the top of the screen + * and redisplay the screen. + */ + prepaint(position(TOP)); +} + +/* + * Jump to the end of the file. + * It is more convenient to paint the screen backward, + * from the end of the file toward the beginning. + */ +jump_forw() +{ + off_t pos; + + if (ch_end_seek()) + { + error("Cannot seek to end of file"); + return; + } + lastmark(); + pos = ch_tell(); + clear(); + pos_clear(); + add_back_pos(pos); + back(sc_height - 1, pos, 0); +} + +/* + * Jump to line n in the file. + */ +jump_back(n) + register int n; +{ + register int c, nlines; + + /* + * This is done the slow way, by starting at the beginning + * of the file and counting newlines. + * + * {{ Now that we have line numbering (in linenum.c), + * we could improve on this by starting at the + * nearest known line rather than at the beginning. }} + */ + if (ch_seek((off_t)0)) { + /* + * Probably a pipe with beginning of file no longer buffered. + * If he wants to go to line 1, we do the best we can, + * by going to the first line which is still buffered. + */ + if (n <= 1 && ch_beg_seek() == 0) + jump_loc(ch_tell()); + error("Cannot get to beginning of file"); + return; + } + + /* + * Start counting lines. + */ + for (nlines = 1; nlines < n; nlines++) + while ((c = ch_forw_get()) != '\n') + if (c == EOI) { + char message[40]; + (void)sprintf(message, "File has only %d lines", + nlines - 1); + error(message); + return; + } + jump_loc(ch_tell()); +} + +/* + * Jump to a specified percentage into the file. + * This is a poor compensation for not being able to + * quickly jump to a specific line number. + */ +jump_percent(percent) + int percent; +{ + off_t pos, len, ch_length(); + register int c; + + /* + * Determine the position in the file + * (the specified percentage of the file's length). + */ + if ((len = ch_length()) == NULL_POSITION) + { + error("Don't know length of file"); + return; + } + pos = (percent * len) / 100; + + /* + * Back up to the beginning of the line. + */ + if (ch_seek(pos) == 0) + { + while ((c = ch_back_get()) != '\n' && c != EOI) + ; + if (c == '\n') + (void) ch_forw_get(); + pos = ch_tell(); + } + jump_loc(pos); +} + +/* + * Jump to a specified position in the file. + */ +jump_loc(pos) + off_t pos; +{ + register int nline; + off_t tpos; + + if ((nline = onscreen(pos)) >= 0) { + /* + * The line is currently displayed. + * Just scroll there. + */ + forw(nline, position(BOTTOM_PLUS_ONE), 0); + return; + } + + /* + * Line is not on screen. + * Seek to the desired location. + */ + if (ch_seek(pos)) { + error("Cannot seek to that position"); + return; + } + + /* + * See if the desired line is BEFORE the currently displayed screen. + * If so, then move forward far enough so the line we're on will be + * at the bottom of the screen, in order to be able to call back() + * to make the screen scroll backwards & put the line at the top of + * the screen. + * {{ This seems inefficient, but it's not so bad, + * since we can never move forward more than a + * screenful before we stop to redraw the screen. }} + */ + tpos = position(TOP); + if (tpos != NULL_POSITION && pos < tpos) { + off_t npos = pos; + /* + * Note that we can't forw_line() past tpos here, + * so there should be no EOI at this stage. + */ + for (nline = 0; npos < tpos && nline < sc_height - 1; nline++) + npos = forw_line(npos); + + if (npos < tpos) { + /* + * More than a screenful back. + */ + lastmark(); + clear(); + pos_clear(); + add_back_pos(npos); + } + + /* + * Note that back() will repaint() if nline > back_scroll. + */ + back(nline, npos, 0); + return; + } + /* + * Remember where we were; clear and paint the screen. + */ + lastmark(); + prepaint(pos); +} + +/* + * The table of marks. + * A mark is simply a position in the file. + */ +#define NMARKS (27) /* 26 for a-z plus one for quote */ +#define LASTMARK (NMARKS-1) /* For quote */ +static off_t marks[NMARKS]; + +/* + * Initialize the mark table to show no marks are set. + */ +init_mark() +{ + int i; + + for (i = 0; i < NMARKS; i++) + marks[i] = NULL_POSITION; +} + +/* + * See if a mark letter is valid (between a and z). + */ + static int +badmark(c) + int c; +{ + if (c < 'a' || c > 'z') + { + error("Choose a letter between 'a' and 'z'"); + return (1); + } + return (0); +} + +/* + * Set a mark. + */ +setmark(c) + int c; +{ + if (badmark(c)) + return; + marks[c-'a'] = position(TOP); +} + +lastmark() +{ + marks[LASTMARK] = position(TOP); +} + +/* + * Go to a previously set mark. + */ +gomark(c) + int c; +{ + off_t pos; + + if (c == '\'') { + pos = marks[LASTMARK]; + if (pos == NULL_POSITION) + pos = 0; + } + else { + if (badmark(c)) + return; + pos = marks[c-'a']; + if (pos == NULL_POSITION) { + error("mark not set"); + return; + } + } + jump_loc(pos); +} + +/* + * Get the backwards scroll limit. + * Must call this function instead of just using the value of + * back_scroll, because the default case depends on sc_height and + * top_scroll, as well as back_scroll. + */ +get_back_scroll() +{ + if (back_scroll >= 0) + return (back_scroll); + if (top_scroll) + return (sc_height - 2); + return (sc_height - 1); +} + +/* + * Search for the n-th occurence of a specified pattern, + * either forward or backward. + */ +search(search_forward, pattern, n, wantmatch) + register int search_forward; + register char *pattern; + register int n; + int wantmatch; +{ + off_t pos, linepos; + register char *p; + register char *q; + int linenum; + int linematch; +#ifdef RECOMP + char *re_comp(); + char *errmsg; +#else +#ifdef REGCMP + char *regcmp(); + static char *cpattern = NULL; +#else + static char lpbuf[100]; + static char *last_pattern = NULL; + char *strcpy(); +#endif +#endif + + /* + * For a caseless search, convert any uppercase in the pattern to + * lowercase. + */ + if (caseless && pattern != NULL) + for (p = pattern; *p; p++) + if (isupper(*p)) + *p = tolower(*p); +#ifdef RECOMP + + /* + * (re_comp handles a null pattern internally, + * so there is no need to check for a null pattern here.) + */ + if ((errmsg = re_comp(pattern)) != NULL) + { + error(errmsg); + return(0); + } +#else +#ifdef REGCMP + if (pattern == NULL || *pattern == '\0') + { + /* + * A null pattern means use the previous pattern. + * The compiled previous pattern is in cpattern, so just use it. + */ + if (cpattern == NULL) + { + error("No previous regular expression"); + return(0); + } + } else + { + /* + * Otherwise compile the given pattern. + */ + char *s; + if ((s = regcmp(pattern, 0)) == NULL) + { + error("Invalid pattern"); + return(0); + } + if (cpattern != NULL) + free(cpattern); + cpattern = s; + } +#else + if (pattern == NULL || *pattern == '\0') + { + /* + * Null pattern means use the previous pattern. + */ + if (last_pattern == NULL) + { + error("No previous regular expression"); + return(0); + } + pattern = last_pattern; + } else + { + (void)strcpy(lpbuf, pattern); + last_pattern = lpbuf; + } +#endif +#endif + + /* + * Figure out where to start the search. + */ + + if (position(TOP) == NULL_POSITION) { + /* + * Nothing is currently displayed. Start at the beginning + * of the file. (This case is mainly for searches from the + * command line. + */ + pos = (off_t)0; + } else if (!search_forward) { + /* + * Backward search: start just before the top line + * displayed on the screen. + */ + pos = position(TOP); + } else { + /* + * Start at the second screen line displayed on the screen. + */ + pos = position(TOP_PLUS_ONE); + } + + if (pos == NULL_POSITION) + { + /* + * Can't find anyplace to start searching from. + */ + error("Nothing to search"); + return(0); + } + + linenum = find_linenum(pos); + for (;;) + { + /* + * Get lines until we find a matching one or + * until we hit end-of-file (or beginning-of-file + * if we're going backwards). + */ + if (sigs) + /* + * A signal aborts the search. + */ + return(0); + + if (search_forward) + { + /* + * Read the next line, and save the + * starting position of that line in linepos. + */ + linepos = pos; + pos = forw_raw_line(pos); + if (linenum != 0) + linenum++; + } else + { + /* + * Read the previous line and save the + * starting position of that line in linepos. + */ + pos = back_raw_line(pos); + linepos = pos; + if (linenum != 0) + linenum--; + } + + if (pos == NULL_POSITION) + { + /* + * We hit EOF/BOF without a match. + */ + error("Pattern not found"); + return(0); + } + + /* + * If we're using line numbers, we might as well + * remember the information we have now (the position + * and line number of the current line). + */ + if (linenums) + add_lnum(linenum, pos); + + /* + * If this is a caseless search, convert uppercase in the + * input line to lowercase. + */ + if (caseless) + for (p = q = line; *p; p++, q++) + *q = isupper(*p) ? tolower(*p) : *p; + + /* + * Remove any backspaces along with the preceeding char. + * This allows us to match text which is underlined or + * overstruck. + */ + for (p = q = line; *p; p++, q++) + if (q > line && *p == '\b') + /* Delete BS and preceeding char. */ + q -= 2; + else + /* Otherwise, just copy. */ + *q = *p; + + /* + * Test the next line to see if we have a match. + * This is done in a variety of ways, depending + * on what pattern matching functions are available. + */ +#ifdef REGCMP + linematch = (regex(cpattern, line) != NULL); +#else +#ifdef RECOMP + linematch = (re_exec(line) == 1); +#else + linematch = match(pattern, line); +#endif +#endif + /* + * We are successful if wantmatch and linematch are + * both true (want a match and got it), + * or both false (want a non-match and got it). + */ + if (((wantmatch && linematch) || (!wantmatch && !linematch)) && + --n <= 0) + /* + * Found the line. + */ + break; + } + jump_loc(linepos); + return(1); +} + +#if !defined(REGCMP) && !defined(RECOMP) +/* + * We have neither regcmp() nor re_comp(). + * We use this function to do simple pattern matching. + * It supports no metacharacters like *, etc. + */ +static +match(pattern, buf) + char *pattern, *buf; +{ + register char *pp, *lp; + + for ( ; *buf != '\0'; buf++) + { + for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) + if (*pp == '\0' || *lp == '\0') + break; + if (*pp == '\0') + return (1); + } + return (0); +} +#endif diff --git a/usr.bin/more/screen.c b/usr.bin/more/screen.c new file mode 100644 index 0000000..edfae1e --- /dev/null +++ b/usr.bin/more/screen.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)screen.c 8.2 (Berkeley) 4/20/94"; +#endif /* not lint */ + +/* + * Routines which deal with the characteristics of the terminal. + * Uses termcap to be as terminal-independent as possible. + * + * {{ Someday this should be rewritten to use curses. }} + */ + +#include +#include + +#define TERMIOS 1 + +#if TERMIO +#include +#else +#if TERMIOS +#include +#define TAB3 0 +#include +#else +#include +#endif +#endif + +#ifdef TIOCGWINSZ +#include +#else +/* + * For the Unix PC (ATT 7300 & 3B1): + * Since WIOCGETD is defined in sys/window.h, we can't use that to decide + * whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead. + */ +#include +#ifdef SIGPHONE +#include +#endif +#endif + +/* + * Strings passed to tputs() to do various terminal functions. + */ +static char + *sc_pad, /* Pad string */ + *sc_home, /* Cursor home */ + *sc_addline, /* Add line, scroll down following lines */ + *sc_lower_left, /* Cursor to last line, first column */ + *sc_move, /* General cursor positioning */ + *sc_clear, /* Clear screen */ + *sc_eol_clear, /* Clear to end of line */ + *sc_s_in, /* Enter standout (highlighted) mode */ + *sc_s_out, /* Exit standout mode */ + *sc_u_in, /* Enter underline mode */ + *sc_u_out, /* Exit underline mode */ + *sc_b_in, /* Enter bold mode */ + *sc_b_out, /* Exit bold mode */ + *sc_backspace, /* Backspace cursor */ + *sc_init, /* Startup terminal initialization */ + *sc_deinit; /* Exit terminal de-intialization */ + +int auto_wrap; /* Terminal does \r\n when write past margin */ +int ignaw; /* Terminal ignores \n immediately after wrap */ + /* The user's erase and line-kill chars */ +int retain_below; /* Terminal retains text below the screen */ +int erase_char, kill_char, werase_char; +int sc_width, sc_height = -1; /* Height & width of screen */ +int sc_window = -1; /* window size for forward and backward */ +int bo_width, be_width; /* Printing width of boldface sequences */ +int ul_width, ue_width; /* Printing width of underline sequences */ +int so_width, se_width; /* Printing width of standout sequences */ + +/* + * These two variables are sometimes defined in, + * and needed by, the termcap library. + * It may be necessary on some systems to declare them extern here. + */ +/*extern*/ short ospeed; /* Terminal output baud rate */ +/*extern*/ char PC; /* Pad character */ + +extern int back_scroll; +char *tgetstr(); +char *tgoto(); + +/* + * Change terminal to "raw mode", or restore to "normal" mode. + * "Raw mode" means + * 1. An outstanding read will complete on receipt of a single keystroke. + * 2. Input is not echoed. + * 3. On output, \n is mapped to \r\n. + * 4. \t is NOT expanded into spaces. + * 5. Signal-causing characters such as ctrl-C (interrupt), + * etc. are NOT disabled. + * It doesn't matter whether an input \n is mapped to \r, or vice versa. + */ +raw_mode(on) + int on; +{ +#if TERMIO || TERMIOS + +#if TERMIO + struct termio s; + static struct termio save_term; +#else + struct termios s; + static struct termios save_term; +#endif + + if (on) + { + /* + * Get terminal modes. + */ +#if TERMIO + (void)ioctl(2, TCGETA, &s); +#else + tcgetattr(2, &s); +#endif + + /* + * Save modes and set certain variables dependent on modes. + */ + save_term = s; +#if TERMIO + ospeed = s.c_cflag & CBAUD; +#else + ospeed = cfgetospeed(&s); +#endif + erase_char = s.c_cc[VERASE]; + kill_char = s.c_cc[VKILL]; + werase_char = s.c_cc[VWERASE]; + + /* + * Set the modes to the way we want them. + */ + s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); + s.c_oflag |= (OPOST|ONLCR|TAB3); +#if TERMIO + s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); +#endif + s.c_cc[VMIN] = 1; + s.c_cc[VTIME] = 0; + } else + { + /* + * Restore saved modes. + */ + s = save_term; + } +#if TERMIO + (void)ioctl(2, TCSETAW, &s); +#else + tcsetattr(2, TCSADRAIN, &s); +#endif +#else + struct sgttyb s; + struct ltchars l; + static struct sgttyb save_term; + + if (on) + { + /* + * Get terminal modes. + */ + (void)ioctl(2, TIOCGETP, &s); + (void)ioctl(2, TIOCGLTC, &l); + + /* + * Save modes and set certain variables dependent on modes. + */ + save_term = s; + ospeed = s.sg_ospeed; + erase_char = s.sg_erase; + kill_char = s.sg_kill; + werase_char = l.t_werasc; + + /* + * Set the modes to the way we want them. + */ + s.sg_flags |= CBREAK; + s.sg_flags &= ~(ECHO|XTABS); + } else + { + /* + * Restore saved modes. + */ + s = save_term; + } + (void)ioctl(2, TIOCSETN, &s); +#endif +} + +/* + * Get terminal capabilities via termcap. + */ +get_term() +{ + char termbuf[2048]; + char *sp; + char *term; + int hard; +#ifdef TIOCGWINSZ + struct winsize w; +#else +#ifdef WIOCGETD + struct uwdata w; +#endif +#endif + static char sbuf[1024]; + + char *getenv(), *strcpy(); + + /* + * Find out what kind of terminal this is. + */ + if ((term = getenv("TERM")) == NULL) + term = "unknown"; + if (tgetent(termbuf, term) <= 0) + (void)strcpy(termbuf, "dumb:co#80:hc:"); + + /* + * Get size of the screen. + */ +#ifdef TIOCGWINSZ + if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0) + sc_height = w.ws_row; +#else +#ifdef WIOCGETD + if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0) + sc_height = w.uw_height/w.uw_vs; +#endif +#endif + else + sc_height = tgetnum("li"); + hard = (sc_height < 0 || tgetflag("hc")); + if (hard) { + /* Oh no, this is a hardcopy terminal. */ + sc_height = 24; + } + +#ifdef TIOCGWINSZ + if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0) + sc_width = w.ws_col; + else +#ifdef WIOCGETD + if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0) + sc_width = w.uw_width/w.uw_hs; + else +#endif +#endif + sc_width = tgetnum("co"); + if (sc_width < 0) + sc_width = 80; + + auto_wrap = tgetflag("am"); + ignaw = tgetflag("xn"); + retain_below = tgetflag("db"); + + /* + * Assumes termcap variable "sg" is the printing width of + * the standout sequence, the end standout sequence, + * the underline sequence, the end underline sequence, + * the boldface sequence, and the end boldface sequence. + */ + if ((so_width = tgetnum("sg")) < 0) + so_width = 0; + be_width = bo_width = ue_width = ul_width = se_width = so_width; + + /* + * Get various string-valued capabilities. + */ + sp = sbuf; + + sc_pad = tgetstr("pc", &sp); + if (sc_pad != NULL) + PC = *sc_pad; + + sc_init = tgetstr("ti", &sp); + if (sc_init == NULL) + sc_init = ""; + + sc_deinit= tgetstr("te", &sp); + if (sc_deinit == NULL) + sc_deinit = ""; + + sc_eol_clear = tgetstr("ce", &sp); + if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0') + { + sc_eol_clear = ""; + } + + sc_clear = tgetstr("cl", &sp); + if (hard || sc_clear == NULL || *sc_clear == '\0') + { + sc_clear = "\n\n"; + } + + sc_move = tgetstr("cm", &sp); + if (hard || sc_move == NULL || *sc_move == '\0') + { + /* + * This is not an error here, because we don't + * always need sc_move. + * We need it only if we don't have home or lower-left. + */ + sc_move = ""; + } + + sc_s_in = tgetstr("so", &sp); + if (hard || sc_s_in == NULL) + sc_s_in = ""; + + sc_s_out = tgetstr("se", &sp); + if (hard || sc_s_out == NULL) + sc_s_out = ""; + + sc_u_in = tgetstr("us", &sp); + if (hard || sc_u_in == NULL) + sc_u_in = sc_s_in; + + sc_u_out = tgetstr("ue", &sp); + if (hard || sc_u_out == NULL) + sc_u_out = sc_s_out; + + sc_b_in = tgetstr("md", &sp); + if (hard || sc_b_in == NULL) + { + sc_b_in = sc_s_in; + sc_b_out = sc_s_out; + } else + { + sc_b_out = tgetstr("me", &sp); + if (hard || sc_b_out == NULL) + sc_b_out = ""; + } + + sc_home = tgetstr("ho", &sp); + if (hard || sc_home == NULL || *sc_home == '\0') + { + if (*sc_move == '\0') + { + /* + * This last resort for sc_home is supposed to + * be an up-arrow suggesting moving to the + * top of the "virtual screen". (The one in + * your imagination as you try to use this on + * a hard copy terminal.) + */ + sc_home = "|\b^"; + } else + { + /* + * No "home" string, + * but we can use "move(0,0)". + */ + (void)strcpy(sp, tgoto(sc_move, 0, 0)); + sc_home = sp; + sp += strlen(sp) + 1; + } + } + + sc_lower_left = tgetstr("ll", &sp); + if (hard || sc_lower_left == NULL || *sc_lower_left == '\0') + { + if (*sc_move == '\0') + { + sc_lower_left = "\r"; + } else + { + /* + * No "lower-left" string, + * but we can use "move(0,last-line)". + */ + (void)strcpy(sp, tgoto(sc_move, 0, sc_height-1)); + sc_lower_left = sp; + sp += strlen(sp) + 1; + } + } + + /* + * To add a line at top of screen and scroll the display down, + * we use "al" (add line) or "sr" (scroll reverse). + */ + if ((sc_addline = tgetstr("al", &sp)) == NULL || + *sc_addline == '\0') + sc_addline = tgetstr("sr", &sp); + + if (hard || sc_addline == NULL || *sc_addline == '\0') + { + sc_addline = ""; + /* Force repaint on any backward movement */ + back_scroll = 0; + } + + if (tgetflag("bs")) + sc_backspace = "\b"; + else + { + sc_backspace = tgetstr("bc", &sp); + if (sc_backspace == NULL || *sc_backspace == '\0') + sc_backspace = "\b"; + } +} + + +/* + * Below are the functions which perform all the + * terminal-specific screen manipulation. + */ + +int putchr(); + +/* + * Initialize terminal + */ +init() +{ + tputs(sc_init, sc_height, putchr); +} + +/* + * Deinitialize terminal + */ +deinit() +{ + tputs(sc_deinit, sc_height, putchr); +} + +/* + * Home cursor (move to upper left corner of screen). + */ +home() +{ + tputs(sc_home, 1, putchr); +} + +/* + * Add a blank line (called with cursor at home). + * Should scroll the display down. + */ +add_line() +{ + tputs(sc_addline, sc_height, putchr); +} + +int short_file; /* if file less than a screen */ +lower_left() +{ + if (short_file) { + putchr('\r'); + flush(); + } + else + tputs(sc_lower_left, 1, putchr); +} + +/* + * Ring the terminal bell. + */ +bell() +{ + putchr('\7'); +} + +/* + * Clear the screen. + */ +clear() +{ + tputs(sc_clear, sc_height, putchr); +} + +/* + * Clear from the cursor to the end of the cursor's line. + * {{ This must not move the cursor. }} + */ +clear_eol() +{ + tputs(sc_eol_clear, 1, putchr); +} + +/* + * Begin "standout" (bold, underline, or whatever). + */ +so_enter() +{ + tputs(sc_s_in, 1, putchr); +} + +/* + * End "standout". + */ +so_exit() +{ + tputs(sc_s_out, 1, putchr); +} + +/* + * Begin "underline" (hopefully real underlining, + * otherwise whatever the terminal provides). + */ +ul_enter() +{ + tputs(sc_u_in, 1, putchr); +} + +/* + * End "underline". + */ +ul_exit() +{ + tputs(sc_u_out, 1, putchr); +} + +/* + * Begin "bold" + */ +bo_enter() +{ + tputs(sc_b_in, 1, putchr); +} + +/* + * End "bold". + */ +bo_exit() +{ + tputs(sc_b_out, 1, putchr); +} + +/* + * Erase the character to the left of the cursor + * and move the cursor left. + */ +backspace() +{ + /* + * Try to erase the previous character by overstriking with a space. + */ + tputs(sc_backspace, 1, putchr); + putchr(' '); + tputs(sc_backspace, 1, putchr); +} + +/* + * Output a plain backspace, without erasing the previous char. + */ +putbs() +{ + tputs(sc_backspace, 1, putchr); +} diff --git a/usr.bin/more/signal.c b/usr.bin/more/signal.c new file mode 100644 index 0000000..67d7e51 --- /dev/null +++ b/usr.bin/more/signal.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)signal.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines dealing with signals. + * + * A signal usually merely causes a bit to be set in the "signals" word. + * At some convenient time, the mainline code checks to see if any + * signals need processing by calling psignal(). + * If we happen to be reading from a file [in iread()] at the time + * the signal is received, we call intread to interrupt the iread. + */ + +#include +#include + +/* + * "sigs" contains bits indicating signals which need to be processed. + */ +int sigs; + +#ifdef SIGTSTP +#define S_STOP 02 +#endif +#if defined(SIGWINCH) || defined(SIGWIND) +#define S_WINCH 04 +#endif + +extern int sc_width, sc_height; +extern int screen_trashed; +extern int lnloop; +extern int linenums; +extern int scroll; +extern int reading; + +#ifdef SIGTSTP +/* + * "Stop" (^Z) signal handler. + */ +static void +stop() +{ + (void)signal(SIGTSTP, stop); + sigs |= S_STOP; + if (reading) + intread(); +} +#endif + +#ifdef SIGWINCH +/* + * "Window" change handler + */ +void +winch() +{ + (void)signal(SIGWINCH, winch); + sigs |= S_WINCH; + if (reading) + intread(); +} +#else +#ifdef SIGWIND +/* + * "Window" change handler + */ +winch() +{ + (void)signal(SIGWIND, winch); + sigs |= S_WINCH; + if (reading) + intread(); +} +#endif +#endif + +static void +purgeandquit() +{ + + purge(); /* purge buffered output */ + quit(); +} + +/* + * Set up the signal handlers. + */ +init_signals(on) + int on; +{ + if (on) + { + /* + * Set signal handlers. + */ + (void)signal(SIGINT, purgeandquit); +#ifdef SIGTSTP + (void)signal(SIGTSTP, stop); +#endif +#ifdef SIGWINCH + (void)signal(SIGWINCH, winch); +#else +#ifdef SIGWIND + (void)signal(SIGWIND, winch); +#endif +#endif + } else + { + /* + * Restore signals to defaults. + */ + (void)signal(SIGINT, SIG_DFL); +#ifdef SIGTSTP + (void)signal(SIGTSTP, SIG_DFL); +#endif +#ifdef SIGWINCH + (void)signal(SIGWINCH, SIG_IGN); +#endif +#ifdef SIGWIND + (void)signal(SIGWIND, SIG_IGN); +#endif + } +} + +/* + * Process any signals we have received. + * A received signal cause a bit to be set in "sigs". + */ +psignals() +{ + register int tsignals; + + if ((tsignals = sigs) == 0) + return; + sigs = 0; + +#ifdef S_WINCH + if (tsignals & S_WINCH) + { + int old_width, old_height; + /* + * Re-execute get_term() to read the new window size. + */ + old_width = sc_width; + old_height = sc_height; + get_term(); + if (sc_width != old_width || sc_height != old_height) + { + scroll = (sc_height + 1) / 2; + screen_trashed = 1; + } + } +#endif +#ifdef SIGTSTP + if (tsignals & S_STOP) + { + /* + * Clean up the terminal. + */ +#ifdef SIGTTOU + (void)signal(SIGTTOU, SIG_IGN); +#endif + lower_left(); + clear_eol(); + deinit(); + (void)flush(); + raw_mode(0); +#ifdef SIGTTOU + (void)signal(SIGTTOU, SIG_DFL); +#endif + (void)signal(SIGTSTP, SIG_DFL); + (void)kill(getpid(), SIGTSTP); + /* + * ... Bye bye. ... + * Hopefully we'll be back later and resume here... + * Reset the terminal and arrange to repaint the + * screen when we get back to the main command loop. + */ + (void)signal(SIGTSTP, stop); + raw_mode(1); + init(); + screen_trashed = 1; + } +#endif +} diff --git a/usr.bin/more/tags.c b/usr.bin/more/tags.c new file mode 100644 index 0000000..029557e --- /dev/null +++ b/usr.bin/more/tags.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)tags.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#define WHITESP(c) ((c)==' ' || (c)=='\t') + +char *tagfile; +char *tagpattern; + +static char *tags = "tags"; + +extern int linenums; +extern int sigs; +extern char *line; + +/* + * Find a tag in the "tags" file. + * Sets "tagfile" to the name of the file containing the tag, + * and "tagpattern" to the search pattern which should be used + * to find the tag. + */ +findtag(tag) + register char *tag; +{ + register char *p; + register FILE *f; + register int taglen; + int search_char; + static char tline[200]; + + if ((f = fopen(tags, "r")) == NULL) + { + error("No tags file"); + tagfile = NULL; + return; + } + + taglen = strlen(tag); + + /* + * Search the tags file for the desired tag. + */ + while (fgets(tline, sizeof(tline), f) != NULL) + { + if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen])) + continue; + + /* + * Found it. + * The line contains the tag, the filename and the + * pattern, separated by white space. + * The pattern is surrounded by a pair of identical + * search characters. + * Parse the line and extract these parts. + */ + tagfile = tagpattern = NULL; + + /* + * Skip over the whitespace after the tag name. + */ + for (p = tline; !WHITESP(*p) && *p != '\0'; p++) + continue; + while (WHITESP(*p)) + p++; + if (*p == '\0') + /* File name is missing! */ + continue; + + /* + * Save the file name. + * Skip over the whitespace after the file name. + */ + tagfile = p; + while (!WHITESP(*p) && *p != '\0') + p++; + *p++ = '\0'; + while (WHITESP(*p)) + p++; + if (*p == '\0') + /* Pattern is missing! */ + continue; + + /* + * Save the pattern. + * Skip to the end of the pattern. + * Delete the initial "^" and the final "$" from the pattern. + */ + search_char = *p++; + if (*p == '^') + p++; + tagpattern = p; + while (*p != search_char && *p != '\0') + p++; + if (p[-1] == '$') + p--; + *p = '\0'; + + (void)fclose(f); + return; + } + (void)fclose(f); + error("No such tag in tags file"); + tagfile = NULL; +} + +/* + * Search for a tag. + * This is a stripped-down version of search(). + * We don't use search() for several reasons: + * - We don't want to blow away any search string we may have saved. + * - The various regular-expression functions (from different systems: + * regcmp vs. re_comp) behave differently in the presence of + * parentheses (which are almost always found in a tag). + */ +tagsearch() +{ + off_t pos, linepos, forw_raw_line(); + int linenum; + + pos = (off_t)0; + linenum = find_linenum(pos); + + for (;;) + { + /* + * Get lines until we find a matching one or + * until we hit end-of-file. + */ + if (sigs) + return (1); + + /* + * Read the next line, and save the + * starting position of that line in linepos. + */ + linepos = pos; + pos = forw_raw_line(pos); + if (linenum != 0) + linenum++; + + if (pos == NULL_POSITION) + { + /* + * We hit EOF without a match. + */ + error("Tag not found"); + return (1); + } + + /* + * If we're using line numbers, we might as well + * remember the information we have now (the position + * and line number of the current line). + */ + if (linenums) + add_lnum(linenum, pos); + + /* + * Test the line to see if we have a match. + */ + if (strcmp(tagpattern, line) == 0) + break; + } + + jump_loc(linepos); + return (0); +} diff --git a/usr.bin/more/ttyin.c b/usr.bin/more/ttyin.c new file mode 100644 index 0000000..52ff92e --- /dev/null +++ b/usr.bin/more/ttyin.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 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[] = "@(#)ttyin.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines dealing with getting input from the keyboard (i.e. from the user). + */ + +#include + +static int tty; + +/* + * Open keyboard for input. + * (Just use file descriptor 2.) + */ +open_getchr() +{ + tty = 2; +} + +/* + * Get a character from the keyboard. + */ +getchr() +{ + char c; + int result; + + do + { + result = iread(tty, &c, 1); + if (result == READ_INTR) + return (READ_INTR); + if (result < 0) + { + /* + * Don't call error() here, + * because error calls getchr! + */ + quit(); + } + } while (result != 1); + return (c & 0177); +} diff --git a/usr.bin/msgs/Makefile b/usr.bin/msgs/Makefile new file mode 100644 index 0000000..09ef68d --- /dev/null +++ b/usr.bin/msgs/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= msgs +DPADD= ${LIBTERM} ${LIBCOMPAT} +LDADD= -ltermlib -lcompat + +.include diff --git a/usr.bin/msgs/msgs.1 b/usr.bin/msgs/msgs.1 new file mode 100644 index 0000000..87d826a --- /dev/null +++ b/usr.bin/msgs/msgs.1 @@ -0,0 +1,214 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)msgs.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MSGS 1 +.Os BSD 4 +.Sh NAME +.Nm msgs +.Nd system messages and junk mail program +.Sh SYNOPSIS +.Nm msgs +.Op Fl fhlpq +.Op Ar number +.Op Ar \-number +.Nm msgs +.Op Fl s +.Nm msgs +.Op Fl c +.Op \-days +.Sh DESCRIPTION +.Nm Msgs +is used to read system messages. +These messages are +sent by mailing to the login `msgs' and should be short +pieces of information which are suitable to be read once by most users +of the system. +.Pp +.Nm Msgs +is normally invoked each time you login, by placing it in the file +.Pa .login +(or +.Pa .profile +if you use +.Xr sh 1 ) . +It will then prompt you with the source and subject of each new message. +If there is no subject line, the first few non-blank lines of the +message will be displayed. +If there is more to the message, you will be told how +long it is and asked whether you wish to see the rest of the message. +The possible responses are: +.Bl -tag -width Fl +.It Fl y +Type the rest of the message. +.It Ic RETURN +Synonym for y. +.It Fl n +Skip this message +and go on to the next message. +.It Fl +Redisplay the last message. +.It Fl q +Drop out of +.Nm msgs ; +the next time +.Nm msgs +will pick up where it last left off. +.It Fl s +Append the current message to the file ``Messages'' in the current directory; +`s\-' will save the previously displayed message. A `s' or `s\-' may +be followed by a space and a file name to receive the message replacing +the default ``Messages''. +.It Fl m +A copy of the specified message is placed in a temporary +mailbox and +.Xr mail 1 +is invoked on that mailbox. +Both `m' and `s' accept a numeric argument in place of the `\-'. +.El +.Pp +.Nm Msgs +keeps track of the next message you will see by a number in the file +.Pa \&.msgsrc +in your home directory. +In the directory +.Pa /var/msgs +it keeps a set of files whose names are the (sequential) numbers +of the messages they represent. +The file +.Pa /var/msgs/bounds +shows the low and high number of the messages in the directory +so that +.Nm msgs +can quickly determine if there are no messages for you. +If the contents of +.Pa bounds +is incorrect it can be fixed by removing it; +.Nm msgs +will make a new +.Pa bounds +file the next time it is run. +.Pp +The +.Fl s +option is used for setting up the posting of messages. The line +.Pp +.Dl msgs: \&"\&| /usr/ucb/msgs \-s\&" +.Pp +should be included in +.Pa /etc/aliases +(see +.Xr newaliases 1 ) +to enable posting of messages. +.Pp +The +.Fl c +option is used for performing cleanup on +.Pa /var/msgs. +An entry with the +.Fl c +option should be placed in +.Pa /etc/crontab +to run every night. This will remove all messages over 21 days old. +A different expiration may be specified on the command line to override +the default. +.Pp +Options when reading messages include: +.Bl -tag -width Fl +.It Fl f +Do not to say ``No new messages.''. +This is useful in a +.Pa .login +file since this is often the case here. +.It Fl q +Queries whether there are messages, printing +``There are new messages.'' if there are. +The command ``msgs \-q'' is often used in login scripts. +.It Fl h +Print the first part of messages only. +.It Fl l +Option causes only locally originated messages to be reported. +.It Ar num +A message number can be given +on the command line, causing +.Nm msgs +to start at the specified message rather than at the next message +indicated by your +.Pa \&.msgsrc +file. +Thus +.Pp +.Dl msgs \-h 1 +.Pp +prints the first part of all messages. +.It Ar \-number +Start +.Ar number +messages back from the one indicated in the +.Pa \&.msgsrc +file, useful for reviews of recent messages. +.It Fl p +Pipe long messages through +.Xr more 1 . +.El +.Pp +Within +.Nm msgs +you can also go to any specific message by typing its number when +.Nm msgs +requests input as to what to do. +.Sh ENVIRONMENT +.Nm Msgs +uses the +.Ev HOME +and +.Ev TERM +environment variables for the default home directory and +terminal type. +.Sh FILES +.Bl -tag -width /usr/msgs/* -compact +.It Pa /usr/msgs/* +database +.It ~/.msgsrc +number of next message to be presented +.El +.Sh SEE ALSO +.Xr aliases 5 , +.\".Xr crontab 5 , +.Xr mail 1 , +.Xr more 1 +.Sh HISTORY +The +.Nm msgs +command appeared in +.Bx 3.0 . diff --git a/usr.bin/msgs/msgs.c b/usr.bin/msgs/msgs.c new file mode 100644 index 0000000..9a5311a --- /dev/null +++ b/usr.bin/msgs/msgs.c @@ -0,0 +1,863 @@ +/*- + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * msgs - a user bulletin board program + * + * usage: + * msgs [fhlopq] [[-]number] to read messages + * msgs -s to place messages + * msgs -c [-days] to clean up the bulletin board + * + * prompt commands are: + * y print message + * n flush message, go to next message + * q flush message, quit + * p print message, turn on 'pipe thru more' mode + * P print message, turn off 'pipe thru more' mode + * - reprint last message + * s[-][] [] save message + * m[-][] mail with message in temp mbox + * x exit without flushing this message + * print message number + */ + +#define V7 /* will look for TERM in the environment */ +#define OBJECT /* will object to messages without Subjects */ +/* #define REJECT /* will reject messages without Subjects + (OBJECT must be defined also) */ +/* #define UNBUFFERED /* use unbuffered output */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +#define CMODE 0666 /* bounds file creation mode */ +#define NO 0 +#define YES 1 +#define SUPERUSER 0 /* superuser uid */ +#define DAEMON 1 /* daemon uid */ +#define NLINES 24 /* default number of lines/crt screen */ +#define NDAYS 21 /* default keep time for messages */ +#define DAYS *24*60*60 /* seconds/day */ +#define MSGSRC ".msgsrc" /* user's rc file */ +#define BOUNDS "bounds" /* message bounds file */ +#define NEXT "Next message? [yq]" +#define MORE "More? [ynq]" +#define NOMORE "(No more) [q] ?" + +typedef char bool; + +FILE *msgsrc; +FILE *newmsg; +char *sep = "-"; +char inbuf[BUFSIZ]; +char fname[128]; +char cmdbuf[128]; +char subj[128]; +char from[128]; +char date[128]; +char *ptr; +char *in; +bool local; +bool ruptible; +bool totty; +bool seenfrom; +bool seensubj; +bool blankline; +bool printing = NO; +bool mailing = NO; +bool quitit = NO; +bool sending = NO; +bool intrpflg = NO; +int uid; +int msg; +int prevmsg; +int lct; +int nlines; +int Lpp = 0; +time_t t; +time_t keep; +struct sgttyb otty; + +char *mktemp(); +char *nxtfld(); +void onintr(); +void onsusp(); + +/* option initialization */ +bool hdrs = NO; +bool qopt = NO; +bool hush = NO; +bool send_msg = NO; +bool locomode = NO; +bool use_pager = NO; +bool clean = NO; +bool lastcmd = NO; +jmp_buf tstpbuf; + +main(argc, argv) +int argc; char *argv[]; +{ + bool newrc, already; + int rcfirst = 0; /* first message to print (from .rc) */ + int rcback = 0; /* amount to back off of rcfirst */ + int firstmsg, nextmsg, lastmsg = 0; + int blast = 0; + FILE *bounds; + +#ifdef UNBUFFERED + setbuf(stdout, NULL); +#endif + + gtty(fileno(stdout), &otty); + time(&t); + setuid(uid = getuid()); + ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL); + if (ruptible) + signal(SIGINT, SIG_DFL); + + argc--, argv++; + while (argc > 0) { + if (isdigit(argv[0][0])) { /* starting message # */ + rcfirst = atoi(argv[0]); + } + else if (isdigit(argv[0][1])) { /* backward offset */ + rcback = atoi( &( argv[0][1] ) ); + } + else { + ptr = *argv; + while (*ptr) switch (*ptr++) { + + case '-': + break; + + case 'c': + if (uid != SUPERUSER && uid != DAEMON) { + fprintf(stderr, "Sorry\n"); + exit(1); + } + clean = YES; + break; + + case 'f': /* silently */ + hush = YES; + break; + + case 'h': /* headers only */ + hdrs = YES; + break; + + case 'l': /* local msgs only */ + locomode = YES; + break; + + case 'o': /* option to save last message */ + lastcmd = YES; + break; + + case 'p': /* pipe thru 'more' during long msgs */ + use_pager = YES; + break; + + case 'q': /* query only */ + qopt = YES; + break; + + case 's': /* sending TO msgs */ + send_msg = YES; + break; + + default: + fprintf(stderr, + "usage: msgs [fhlopq] [[-]number]\n"); + exit(1); + } + } + argc--, argv++; + } + + /* + * determine current message bounds + */ + sprintf(fname, "%s/%s", _PATH_MSGS, BOUNDS); + bounds = fopen(fname, "r"); + + if (bounds != NULL) { + fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg); + fclose(bounds); + blast = lastmsg; /* save upper bound */ + } + + if (clean) + keep = t - (rcback? rcback : NDAYS) DAYS; + + if (clean || bounds == NULL) { /* relocate message bounds */ + struct direct *dp; + struct stat stbuf; + bool seenany = NO; + DIR *dirp; + + dirp = opendir(_PATH_MSGS); + if (dirp == NULL) { + perror(_PATH_MSGS); + exit(errno); + } + + firstmsg = 32767; + lastmsg = 0; + + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){ + register char *cp = dp->d_name; + register int i = 0; + + if (dp->d_ino == 0) + continue; + if (dp->d_namlen == 0) + continue; + + if (clean) + sprintf(inbuf, "%s/%s", _PATH_MSGS, cp); + + while (isdigit(*cp)) + i = i * 10 + *cp++ - '0'; + if (*cp) + continue; /* not a message! */ + + if (clean) { + if (stat(inbuf, &stbuf) != 0) + continue; + if (stbuf.st_mtime < keep + && stbuf.st_mode&S_IWRITE) { + unlink(inbuf); + continue; + } + } + + if (i > lastmsg) + lastmsg = i; + if (i < firstmsg) + firstmsg = i; + seenany = YES; + } + closedir(dirp); + + if (!seenany) { + if (blast != 0) /* never lower the upper bound! */ + lastmsg = blast; + firstmsg = lastmsg + 1; + } + else if (blast > lastmsg) + lastmsg = blast; + + if (!send_msg) { + bounds = fopen(fname, "w"); + if (bounds == NULL) { + perror(fname); + exit(errno); + } + chmod(fname, CMODE); + fprintf(bounds, "%d %d\n", firstmsg, lastmsg); + fclose(bounds); + } + } + + if (send_msg) { + /* + * Send mode - place msgs in _PATH_MSGS + */ + bounds = fopen(fname, "w"); + if (bounds == NULL) { + perror(fname); + exit(errno); + } + + nextmsg = lastmsg + 1; + sprintf(fname, "%s/%d", _PATH_MSGS, nextmsg); + newmsg = fopen(fname, "w"); + if (newmsg == NULL) { + perror(fname); + exit(errno); + } + chmod(fname, 0644); + + fprintf(bounds, "%d %d\n", firstmsg, nextmsg); + fclose(bounds); + + sending = YES; + if (ruptible) + signal(SIGINT, onintr); + + if (isatty(fileno(stdin))) { + ptr = getpwuid(uid)->pw_name; + printf("Message %d:\nFrom %s %sSubject: ", + nextmsg, ptr, ctime(&t)); + fflush(stdout); + fgets(inbuf, sizeof inbuf, stdin); + putchar('\n'); + fflush(stdout); + fprintf(newmsg, "From %s %sSubject: %s\n", + ptr, ctime(&t), inbuf); + blankline = seensubj = YES; + } + else + blankline = seensubj = NO; + for (;;) { + fgets(inbuf, sizeof inbuf, stdin); + if (feof(stdin) || ferror(stdin)) + break; + blankline = (blankline || (inbuf[0] == '\n')); + seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0))); + fputs(inbuf, newmsg); + } +#ifdef OBJECT + if (!seensubj) { + printf("NOTICE: Messages should have a Subject field!\n"); +#ifdef REJECT + unlink(fname); +#endif + exit(1); + } +#endif + exit(ferror(stdin)); + } + if (clean) + exit(0); + + /* + * prepare to display messages + */ + totty = (isatty(fileno(stdout)) != 0); + use_pager = use_pager && totty; + + sprintf(fname, "%s/%s", getenv("HOME"), MSGSRC); + msgsrc = fopen(fname, "r"); + if (msgsrc) { + newrc = NO; + fscanf(msgsrc, "%d\n", &nextmsg); + fclose(msgsrc); + if (nextmsg > lastmsg+1) { + printf("Warning: bounds have been reset (%d, %d)\n", + firstmsg, lastmsg); + truncate(fname, (off_t)0); + newrc = YES; + } + else if (!rcfirst) + rcfirst = nextmsg - rcback; + } + else + newrc = YES; + msgsrc = fopen(fname, "r+"); + if (msgsrc == NULL) + msgsrc = fopen(fname, "w"); + if (msgsrc == NULL) { + perror(fname); + exit(errno); + } + if (rcfirst) { + if (rcfirst > lastmsg+1) { + printf("Warning: the last message is number %d.\n", + lastmsg); + rcfirst = nextmsg; + } + if (rcfirst > firstmsg) + firstmsg = rcfirst; /* don't set below first msg */ + } + if (newrc) { + nextmsg = firstmsg; + fseek(msgsrc, 0L, 0); + fprintf(msgsrc, "%d\n", nextmsg); + fflush(msgsrc); + } + +#ifdef V7 + if (totty) { + struct winsize win; + if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) + Lpp = win.ws_row; + if (Lpp <= 0) { + if (tgetent(inbuf, getenv("TERM")) <= 0 + || (Lpp = tgetnum("li")) <= 0) { + Lpp = NLINES; + } + } + } +#endif + Lpp -= 6; /* for headers, etc. */ + + already = NO; + prevmsg = firstmsg; + printing = YES; + if (ruptible) + signal(SIGINT, onintr); + + /* + * Main program loop + */ + for (msg = firstmsg; msg <= lastmsg; msg++) { + + sprintf(fname, "%s/%d", _PATH_MSGS, msg); + newmsg = fopen(fname, "r"); + if (newmsg == NULL) + continue; + + gfrsub(newmsg); /* get From and Subject fields */ + if (locomode && !local) { + fclose(newmsg); + continue; + } + + if (qopt) { /* This has to be located here */ + printf("There are new messages.\n"); + exit(0); + } + + if (already && !hdrs) + putchar('\n'); + + /* + * Print header + */ + if (totty) + signal(SIGTSTP, onsusp); + (void) setjmp(tstpbuf); + already = YES; + nlines = 2; + if (seenfrom) { + printf("Message %d:\nFrom %s %s", msg, from, date); + nlines++; + } + if (seensubj) { + printf("Subject: %s", subj); + nlines++; + } + else { + if (seenfrom) { + putchar('\n'); + nlines++; + } + while (nlines < 6 + && fgets(inbuf, sizeof inbuf, newmsg) + && inbuf[0] != '\n') { + fputs(inbuf, stdout); + nlines++; + } + } + + lct = linecnt(newmsg); + if (lct) + printf("(%d%slines) ", lct, seensubj? " " : " more "); + + if (hdrs) { + printf("\n-----\n"); + fclose(newmsg); + continue; + } + + /* + * Ask user for command + */ + if (totty) + ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT)); + else + inbuf[0] = 'y'; + if (totty) + signal(SIGTSTP, SIG_DFL); +cmnd: + in = inbuf; + switch (*in) { + case 'x': + case 'X': + exit(0); + + case 'q': + case 'Q': + quitit = YES; + printf("--Postponed--\n"); + exit(0); + /* intentional fall-thru */ + case 'n': + case 'N': + if (msg >= nextmsg) sep = "Flushed"; + prevmsg = msg; + break; + + case 'p': + case 'P': + use_pager = (*in++ == 'p'); + /* intentional fallthru */ + case '\n': + case 'y': + default: + if (*in == '-') { + msg = prevmsg-1; + sep = "replay"; + break; + } + if (isdigit(*in)) { + msg = next(in); + sep = in; + break; + } + + prmesg(nlines + lct + (seensubj? 1 : 0)); + prevmsg = msg; + + } + + printf("--%s--\n", sep); + sep = "-"; + if (msg >= nextmsg) { + nextmsg = msg + 1; + fseek(msgsrc, 0L, 0); + fprintf(msgsrc, "%d\n", nextmsg); + fflush(msgsrc); + } + if (newmsg) + fclose(newmsg); + if (quitit) + break; + } + + /* + * Make sure .rc file gets updated + */ + if (--msg >= nextmsg) { + nextmsg = msg + 1; + fseek(msgsrc, 0L, 0); + fprintf(msgsrc, "%d\n", nextmsg); + fflush(msgsrc); + } + if (already && !quitit && lastcmd && totty) { + /* + * save or reply to last message? + */ + msg = prevmsg; + ask(NOMORE); + if (inbuf[0] == '-' || isdigit(inbuf[0])) + goto cmnd; + } + if (!(already || hush || qopt)) + printf("No new messages.\n"); + exit(0); +} + +prmesg(length) +int length; +{ + FILE *outf; + + if (use_pager && length > Lpp) { + signal(SIGPIPE, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + sprintf(cmdbuf, _PATH_PAGER, Lpp); + outf = popen(cmdbuf, "w"); + if (!outf) + outf = stdout; + else + setbuf(outf, (char *)NULL); + } + else + outf = stdout; + + if (seensubj) + putc('\n', outf); + + while (fgets(inbuf, sizeof inbuf, newmsg)) { + fputs(inbuf, outf); + if (ferror(outf)) { + clearerr(outf); + break; + } + } + + if (outf != stdout) { + pclose(outf); + signal(SIGPIPE, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + } + else { + fflush(stdout); + } + + /* trick to force wait on output */ + stty(fileno(stdout), &otty); +} + +void +onintr() +{ + signal(SIGINT, onintr); + if (mailing) + unlink(fname); + if (sending) { + unlink(fname); + puts("--Killed--"); + exit(1); + } + if (printing) { + putchar('\n'); + if (hdrs) + exit(0); + sep = "Interrupt"; + if (newmsg) + fseek(newmsg, 0L, 2); + intrpflg = YES; + } +} + +/* + * We have just gotten a susp. Suspend and prepare to resume. + */ +void +onsusp() +{ + + signal(SIGTSTP, SIG_DFL); + sigsetmask(0); + kill(0, SIGTSTP); + signal(SIGTSTP, onsusp); + if (!mailing) + longjmp(tstpbuf, 0); +} + +linecnt(f) +FILE *f; +{ + off_t oldpos = ftell(f); + int l = 0; + char lbuf[BUFSIZ]; + + while (fgets(lbuf, sizeof lbuf, f)) + l++; + clearerr(f); + fseek(f, oldpos, 0); + return (l); +} + +next(buf) +char *buf; +{ + int i; + sscanf(buf, "%d", &i); + sprintf(buf, "Goto %d", i); + return(--i); +} + +ask(prompt) +char *prompt; +{ + char inch; + int n, cmsg; + off_t oldpos; + FILE *cpfrom, *cpto; + + printf("%s ", prompt); + fflush(stdout); + intrpflg = NO; + (void) fgets(inbuf, sizeof inbuf, stdin); + if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n') + inbuf[n - 1] = '\0'; + if (intrpflg) + inbuf[0] = 'x'; + + /* + * Handle 'mail' and 'save' here. + */ + if ((inch = inbuf[0]) == 's' || inch == 'm') { + if (inbuf[1] == '-') + cmsg = prevmsg; + else if (isdigit(inbuf[1])) + cmsg = atoi(&inbuf[1]); + else + cmsg = msg; + sprintf(fname, "%s/%d", _PATH_MSGS, cmsg); + + oldpos = ftell(newmsg); + + cpfrom = fopen(fname, "r"); + if (!cpfrom) { + printf("Message %d not found\n", cmsg); + ask (prompt); + return; + } + + if (inch == 's') { + in = nxtfld(inbuf); + if (*in) { + for (n=0; in[n] > ' '; n++) { /* sizeof fname? */ + fname[n] = in[n]; + } + fname[n] = NULL; + } + else + strcpy(fname, "Messages"); + } + else { + strcpy(fname, _PATH_TMP); + mktemp(fname); + sprintf(cmdbuf, _PATH_MAIL, fname); + mailing = YES; + } + cpto = fopen(fname, "a"); + if (!cpto) { + perror(fname); + mailing = NO; + fseek(newmsg, oldpos, 0); + ask(prompt); + return; + } + + while (n = fread(inbuf, 1, sizeof inbuf, cpfrom)) + fwrite(inbuf, 1, n, cpto); + + fclose(cpfrom); + fclose(cpto); + fseek(newmsg, oldpos, 0); /* reposition current message */ + if (inch == 's') + printf("Message %d saved in \"%s\"\n", cmsg, fname); + else { + system(cmdbuf); + unlink(fname); + mailing = NO; + } + ask(prompt); + } +} + +gfrsub(infile) +FILE *infile; +{ + off_t frompos; + + seensubj = seenfrom = NO; + local = YES; + subj[0] = from[0] = date[0] = NULL; + + /* + * Is this a normal message? + */ + if (fgets(inbuf, sizeof inbuf, infile)) { + if (strncmp(inbuf, "From", 4)==0) { + /* + * expected form starts with From + */ + seenfrom = YES; + frompos = ftell(infile); + ptr = from; + in = nxtfld(inbuf); + if (*in) while (*in && *in > ' ') { + if (*in == ':' || *in == '@' || *in == '!') + local = NO; + *ptr++ = *in++; + /* what about sizeof from ? */ + } + *ptr = NULL; + if (*(in = nxtfld(in))) + strncpy(date, in, sizeof date); + else { + date[0] = '\n'; + date[1] = NULL; + } + } + else { + /* + * not the expected form + */ + fseek(infile, 0L, 0); + return; + } + } + else + /* + * empty file ? + */ + return; + + /* + * look for Subject line until EOF or a blank line + */ + while (fgets(inbuf, sizeof inbuf, infile) + && !(blankline = (inbuf[0] == '\n'))) { + /* + * extract Subject line + */ + if (!seensubj && strncmp(inbuf, "Subj", 4)==0) { + seensubj = YES; + frompos = ftell(infile); + strncpy(subj, nxtfld(inbuf), sizeof subj); + } + } + if (!blankline) + /* + * ran into EOF + */ + fseek(infile, frompos, 0); + + if (!seensubj) + /* + * for possible use with Mail + */ + strncpy(subj, "(No Subject)\n", sizeof subj); +} + +char * +nxtfld(s) +char *s; +{ + if (*s) while (*s && *s > ' ') s++; /* skip over this field */ + if (*s) while (*s && *s <= ' ') s++; /* find start of next field */ + return (s); +} diff --git a/usr.bin/msgs/pathnames.h b/usr.bin/msgs/pathnames.h new file mode 100644 index 0000000..90f23f4 --- /dev/null +++ b/usr.bin/msgs/pathnames.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_MSGS "/var/msgs" +#define _PATH_MAIL "/usr/bin/Mail -f %s" +#define _PATH_PAGER "/usr/bin/more -%d" +#undef _PATH_TMP +#define _PATH_TMP "/tmp/msgXXXXXX" diff --git a/usr.bin/mt/Makefile b/usr.bin/mt/Makefile new file mode 100644 index 0000000..253fa99 --- /dev/null +++ b/usr.bin/mt/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mt +CFLAGS+=-I/sys + +.include diff --git a/usr.bin/mt/mt.1 b/usr.bin/mt/mt.1 new file mode 100644 index 0000000..9edaab6 --- /dev/null +++ b/usr.bin/mt/mt.1 @@ -0,0 +1,130 @@ +.\" Copyright (c) 1981, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mt.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MT 1 +.Os BSD 4 +.Sh NAME +.Nm mt +.Nd magnetic tape manipulating program +.Sh SYNOPSIS +.Nm mt +.Op Fl f Ar tapename +.Ar command +.Op Ar count +.Sh DESCRIPTION +.Nm Mt +is used to give commands to a magnetic tape drive. +By default +.Nm mt +performs the requested operation once. Operations +may be performed multiple times by specifying +.Ar count . +Note +that +.Ar tapename +must reference a raw (not block) tape device. +.Pp +The available commands are listed below. Only as many +characters as are required to uniquely identify a command +need be specified. +.Bl -tag -width "eof, weof" +.It Cm eof , weof +Write +.Ar count +end-of-file marks at the current position on the tape. +.It Cm fsf +Forward space +.Ar count +files. +.It Cm fsr +Forward space +.Ar count +records. +.It Cm bsf +Back space +.Ar count +files. +.It Cm bsr +Back space +.Ar count +records. +.It Cm rewind +Rewind the tape +(Count is ignored). +.It Cm offline , rewoffl +Rewind the tape and place the tape unit off-line +(Count is ignored). +.It Cm status +Print status information about the tape unit. +.El +.Pp +If a tape name is not specified, and the environment variable +.Ev TAPE +does not exist; +.Nm mt +uses the device +.Pa /dev/rmt12 . +.Pp +.Nm Mt +returns a 0 exit status when the operation(s) were successful, +1 if the command was unrecognized, and 2 if an operation failed. +.Sh ENVIRONMENT +If the following environment variable exists, it is utilized by +.Nm mt . +.Bl -tag -width Fl +.It Ev TAPE +.Nm Mt +checks the +.Ev TAPE +environment variable if the +argument +.Ar tapename +is not given. +.Sh FILES +.Bl -tag -width /dev/rmt* -compact +.It Pa /dev/rmt* +Raw magnetic tape interface +.El +.Sh SEE ALSO +.\".Xr mtio 4 , +.Xr dd 1 , +.Xr ioctl 2 , +.Xr environ 7 +.Sh HISTORY +The +.Nm mt +command appeared in +.Bx 4.3 . +.\" mt.1: mtio(4) missing diff --git a/usr.bin/mt/mt.c b/usr.bin/mt/mt.c new file mode 100644 index 0000000..396fa81 --- /dev/null +++ b/usr.bin/mt/mt.c @@ -0,0 +1,274 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mt.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * mt -- + * magnetic tape manipulation program + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct commands { + char *c_name; + int c_code; + int c_ronly; +} com[] = { + { "bsf", MTBSF, 1 }, + { "bsr", MTBSR, 1 }, + { "eof", MTWEOF, 0 }, + { "fsf", MTFSF, 1 }, + { "fsr", MTFSR, 1 }, + { "offline", MTOFFL, 1 }, + { "rewind", MTREW, 1 }, + { "rewoffl", MTOFFL, 1 }, + { "status", MTNOP, 1 }, + { "weof", MTWEOF, 0 }, + { NULL } +}; + +void err __P((const char *, ...)); +void printreg __P((char *, u_int, char *)); +void status __P((struct mtget *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register struct commands *comp; + struct mtget mt_status; + struct mtop mt_com; + int ch, len, mtfd; + char *p, *tape; + + if ((tape = getenv("TAPE")) == NULL) + tape = DEFTAPE; + + while ((ch = getopt(argc, argv, "f:t:")) != EOF) + switch(ch) { + case 'f': + case 't': + tape = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) + usage(); + + len = strlen(p = *argv++); + for (comp = com;; comp++) { + if (comp->c_name == NULL) + err("%s: unknown command", p); + if (strncmp(p, comp->c_name, len) == 0) + break; + } + if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0) + err("%s: %s", tape, strerror(errno)); + if (comp->c_code != MTNOP) { + mt_com.mt_op = comp->c_code; + if (*argv) { + mt_com.mt_count = strtol(*argv, &p, 10); + if (mt_com.mt_count <= 0 || *p) + err("%s: illegal count", *argv); + } + else + mt_com.mt_count = 1; + if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0) + err("%s: %s: %s", tape, comp->c_name, strerror(errno)); + } else { + if (ioctl(mtfd, MTIOCGET, &mt_status) < 0) + err("%s", strerror(errno)); + status(&mt_status); + } + exit (0); + /* NOTREACHED */ +} + +#ifdef vax +#include +#include + +#include +#include +#undef b_repcnt /* argh */ +#include +#endif + +#ifdef sun +#include +#include +#endif + +#ifdef tahoe +#include +#endif + +struct tape_desc { + short t_type; /* type of magtape device */ + char *t_name; /* printing name */ + char *t_dsbits; /* "drive status" register */ + char *t_erbits; /* "error" register */ +} tapes[] = { +#ifdef vax + { MT_ISTS, "ts11", 0, TSXS0_BITS }, + { MT_ISHT, "tm03", HTDS_BITS, HTER_BITS }, + { MT_ISTM, "tm11", 0, TMER_BITS }, + { MT_ISMT, "tu78", MTDS_BITS, 0 }, + { MT_ISUT, "tu45", UTDS_BITS, UTER_BITS }, +#endif +#ifdef sun + { MT_ISCPC, "TapeMaster", TMS_BITS, 0 }, + { MT_ISAR, "Archive", ARCH_CTRL_BITS, ARCH_BITS }, +#endif +#ifdef tahoe + { MT_ISCY, "cipher", CYS_BITS, CYCW_BITS }, +#endif + { 0 } +}; + +/* + * Interpret the status buffer returned + */ +void +status(bp) + register struct mtget *bp; +{ + register struct tape_desc *mt; + + for (mt = tapes;; mt++) { + if (mt->t_type == 0) { + (void)printf("%d: unknown tape drive type\n", + bp->mt_type); + return; + } + if (mt->t_type == bp->mt_type) + break; + } + (void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid); + printreg("ds", bp->mt_dsreg, mt->t_dsbits); + printreg("\ner", bp->mt_erreg, mt->t_erbits); + (void)putchar('\n'); +} + +/* + * Print a register a la the %b format of the kernel's printf. + */ +void +printreg(s, v, bits) + char *s; + register u_int v; + register char *bits; +{ + register int i, any = 0; + register char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + bits++; + if (v && bits) { + putchar('<'); + while (i = *bits++) { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} + +void +usage() +{ + (void)fprintf(stderr, "usage: mt [-f device] command [ count ]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "mt: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile new file mode 100644 index 0000000..51fc9fa --- /dev/null +++ b/usr.bin/netstat/Makefile @@ -0,0 +1,13 @@ +# @(#)Makefile 8.1 (Berkeley) 6/12/93 + +PROG= netstat +SRCS= if.c inet.c iso.c main.c mbuf.c mroute.c ns.c route.c \ + tp_astring.c unix.c +CFLAGS+=-I/sys +.PATH: ${.CURDIR}/../../sys/netiso +BINGRP= kmem +BINMODE=2555 +LDADD= -lkvm +DPADD= ${LIBKVM} + +.include diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c new file mode 100644 index 0000000..3f12f53 --- /dev/null +++ b/usr.bin/netstat/if.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)if.c 8.2 (Berkeley) 2/21/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "netstat.h" + +#define YES 1 +#define NO 0 + +static void sidewaysintpr __P((u_int, u_long)); +static void catchalarm __P((int)); + +/* + * Print a description of the network interfaces. + */ +void +intpr(interval, ifnetaddr) + int interval; + u_long ifnetaddr; +{ + struct ifnet ifnet; + union { + struct ifaddr ifa; + struct in_ifaddr in; + struct ns_ifaddr ns; + struct iso_ifaddr iso; + } ifaddr; + u_long ifaddraddr; + struct sockaddr *sa; + char name[16]; + + if (ifnetaddr == 0) { + printf("ifnet: symbol not defined\n"); + return; + } + if (interval) { + sidewaysintpr((unsigned)interval, ifnetaddr); + return; + } + if (kread(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr)) + return; + printf("%-5.5s %-5.5s %-11.11s %-15.15s %8.8s %5.5s %8.8s %5.5s", + "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", + "Opkts", "Oerrs"); + printf(" %5s", "Coll"); + if (tflag) + printf(" %s", "Time"); + if (dflag) + printf(" %s", "Drop"); + putchar('\n'); + ifaddraddr = 0; + while (ifnetaddr || ifaddraddr) { + struct sockaddr_in *sin; + register char *cp; + int n, m; + + if (ifaddraddr == 0) { + if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) || + kread((u_long)ifnet.if_name, name, 16)) + return; + name[15] = '\0'; + ifnetaddr = (u_long)ifnet.if_next; + if (interface != 0 && (strcmp(name, interface) != 0 || + unit != ifnet.if_unit)) + continue; + cp = index(name, '\0'); + cp += sprintf(cp, "%d", ifnet.if_unit); + if ((ifnet.if_flags&IFF_UP) == 0) + *cp++ = '*'; + *cp = '\0'; + ifaddraddr = (u_long)ifnet.if_addrlist; + } + printf("%-5.5s %-5d ", name, ifnet.if_mtu); + if (ifaddraddr == 0) { + printf("%-11.11s ", "none"); + printf("%-15.15s ", "none"); + } else { + if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { + ifaddraddr = 0; + continue; + } +#define CP(x) ((char *)(x)) + cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + + CP(&ifaddr); sa = (struct sockaddr *)cp; + switch (sa->sa_family) { + case AF_UNSPEC: + printf("%-11.11s ", "none"); + printf("%-15.15s ", "none"); + break; + case AF_INET: + sin = (struct sockaddr_in *)sa; +#ifdef notdef + /* can't use inet_makeaddr because kernel + * keeps nets unshifted. + */ + in = inet_makeaddr(ifaddr.in.ia_subnet, + INADDR_ANY); + printf("%-11.11s ", netname(in.s_addr, + ifaddr.in.ia_subnetmask)); +#else + printf("%-11.11s ", + netname(htonl(ifaddr.in.ia_subnet), + ifaddr.in.ia_subnetmask)); +#endif + printf("%-15.15s ", + routename(sin->sin_addr.s_addr)); + break; + case AF_NS: + { + struct sockaddr_ns *sns = + (struct sockaddr_ns *)sa; + u_long net; + char netnum[8]; + + *(union ns_net *) &net = sns->sns_addr.x_net; + sprintf(netnum, "%lxH", ntohl(net)); + upHex(netnum); + printf("ns:%-8s ", netnum); + printf("%-15s ", + ns_phost((struct sockaddr *)sns)); + } + break; + case AF_LINK: + { + struct sockaddr_dl *sdl = + (struct sockaddr_dl *)sa; + cp = (char *)LLADDR(sdl); + n = sdl->sdl_alen; + } + m = printf(""); + goto hexprint; + default: + m = printf("(%d)", sa->sa_family); + for (cp = sa->sa_len + (char *)sa; + --cp > sa->sa_data && (*cp == 0);) {} + n = cp - sa->sa_data + 1; + cp = sa->sa_data; + hexprint: + while (--n >= 0) + m += printf("%x%c", *cp++ & 0xff, + n > 0 ? '.' : ' '); + m = 28 - m; + while (m-- > 0) + putchar(' '); + break; + } + ifaddraddr = (u_long)ifaddr.ifa.ifa_next; + } + printf("%8d %5d %8d %5d %5d", + ifnet.if_ipackets, ifnet.if_ierrors, + ifnet.if_opackets, ifnet.if_oerrors, + ifnet.if_collisions); + if (tflag) + printf(" %3d", ifnet.if_timer); + if (dflag) + printf(" %3d", ifnet.if_snd.ifq_drops); + putchar('\n'); + } +} + +#define MAXIF 10 +struct iftot { + char ift_name[16]; /* interface name */ + int ift_ip; /* input packets */ + int ift_ie; /* input errors */ + int ift_op; /* output packets */ + int ift_oe; /* output errors */ + int ift_co; /* collisions */ + int ift_dr; /* drops */ +} iftot[MAXIF]; + +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. + */ +static void +sidewaysintpr(interval, off) + unsigned interval; + u_long off; +{ + struct ifnet ifnet; + u_long firstifnet; + register struct iftot *ip, *total; + register int line; + struct iftot *lastif, *sum, *interesting; + int oldmask; + + if (kread(off, (char *)&firstifnet, sizeof (u_long))) + return; + lastif = iftot; + sum = iftot + MAXIF - 1; + total = sum - 1; + interesting = iftot; + for (off = firstifnet, ip = iftot; off;) { + char *cp; + + if (kread(off, (char *)&ifnet, sizeof ifnet)) + break; + ip->ift_name[0] = '('; + if (kread((u_long)ifnet.if_name, ip->ift_name + 1, 15)) + break; + if (interface && strcmp(ip->ift_name + 1, interface) == 0 && + unit == ifnet.if_unit) + interesting = ip; + ip->ift_name[15] = '\0'; + cp = index(ip->ift_name, '\0'); + sprintf(cp, "%d)", ifnet.if_unit); + ip++; + if (ip >= iftot + MAXIF - 2) + break; + off = (u_long) ifnet.if_next; + } + lastif = ip; + + (void)signal(SIGALRM, catchalarm); + signalled = NO; + (void)alarm(interval); +banner: + printf(" input %-6.6s output ", interesting->ift_name); + if (lastif - iftot > 0) { + if (dflag) + printf(" "); + printf(" input (Total) output"); + } + for (ip = iftot; ip < iftot + MAXIF; ip++) { + ip->ift_ip = 0; + ip->ift_ie = 0; + ip->ift_op = 0; + ip->ift_oe = 0; + ip->ift_co = 0; + ip->ift_dr = 0; + } + putchar('\n'); + printf("%8.8s %5.5s %8.8s %5.5s %5.5s ", + "packets", "errs", "packets", "errs", "colls"); + if (dflag) + printf("%5.5s ", "drops"); + if (lastif - iftot > 0) + printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", + "packets", "errs", "packets", "errs", "colls"); + if (dflag) + printf(" %5.5s", "drops"); + putchar('\n'); + fflush(stdout); + line = 0; +loop: + sum->ift_ip = 0; + sum->ift_ie = 0; + sum->ift_op = 0; + sum->ift_oe = 0; + sum->ift_co = 0; + sum->ift_dr = 0; + for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { + if (kread(off, (char *)&ifnet, sizeof ifnet)) { + off = 0; + continue; + } + if (ip == interesting) { + printf("%8d %5d %8d %5d %5d", + ifnet.if_ipackets - ip->ift_ip, + ifnet.if_ierrors - ip->ift_ie, + ifnet.if_opackets - ip->ift_op, + ifnet.if_oerrors - ip->ift_oe, + ifnet.if_collisions - ip->ift_co); + if (dflag) + printf(" %5d", + ifnet.if_snd.ifq_drops - ip->ift_dr); + } + ip->ift_ip = ifnet.if_ipackets; + ip->ift_ie = ifnet.if_ierrors; + ip->ift_op = ifnet.if_opackets; + ip->ift_oe = ifnet.if_oerrors; + ip->ift_co = ifnet.if_collisions; + ip->ift_dr = ifnet.if_snd.ifq_drops; + sum->ift_ip += ip->ift_ip; + sum->ift_ie += ip->ift_ie; + sum->ift_op += ip->ift_op; + sum->ift_oe += ip->ift_oe; + sum->ift_co += ip->ift_co; + sum->ift_dr += ip->ift_dr; + off = (u_long) ifnet.if_next; + } + if (lastif - iftot > 0) { + printf(" %8d %5d %8d %5d %5d", + sum->ift_ip - total->ift_ip, + sum->ift_ie - total->ift_ie, + sum->ift_op - total->ift_op, + sum->ift_oe - total->ift_oe, + sum->ift_co - total->ift_co); + if (dflag) + printf(" %5d", sum->ift_dr - total->ift_dr); + } + *total = *sum; + putchar('\n'); + fflush(stdout); + line++; + oldmask = sigblock(sigmask(SIGALRM)); + if (! signalled) { + sigpause(0); + } + sigsetmask(oldmask); + signalled = NO; + (void)alarm(interval); + if (line == 21) + goto banner; + goto loop; + /*NOTREACHED*/ +} + +/* + * Called if an interval expires before sidewaysintpr has completed a loop. + * Sets a flag to not wait for the alarm. + */ +static void +catchalarm(signo) + int signo; +{ + signalled = YES; +} diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c new file mode 100644 index 0000000..099333e --- /dev/null +++ b/usr.bin/netstat/inet.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TCPSTATES +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "netstat.h" + +struct inpcb inpcb; +struct tcpcb tcpcb; +struct socket sockb; + +char *inetname __P((struct in_addr *)); +void inetprint __P((struct in_addr *, int, char *)); + +/* + * Print a summary of connections related to an Internet + * protocol. For TCP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ +void +protopr(off, name) + u_long off; + char *name; +{ + struct inpcb cb; + register struct inpcb *prev, *next; + int istcp; + static int first = 1; + + if (off == 0) + return; + istcp = strcmp(name, "tcp") == 0; + kread(off, (char *)&cb, sizeof (struct inpcb)); + inpcb = cb; + prev = (struct inpcb *)off; + if (inpcb.inp_next == (struct inpcb *)off) + return; + while (inpcb.inp_next != (struct inpcb *)off) { + next = inpcb.inp_next; + kread((u_long)next, (char *)&inpcb, sizeof (inpcb)); + if (inpcb.inp_prev != prev) { + printf("???\n"); + break; + } + if (!aflag && + inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) { + prev = next; + continue; + } + kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb)); + if (istcp) { + kread((u_long)inpcb.inp_ppcb, + (char *)&tcpcb, sizeof (tcpcb)); + } + if (first) { + printf("Active Internet connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + if (Aflag) + if (istcp) + printf("%8x ", inpcb.inp_ppcb); + else + printf("%8x ", next); + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name); + inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name); + if (istcp) { + if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES) + printf(" %d", tcpcb.t_state); + else + printf(" %s", tcpstates[tcpcb.t_state]); + } + putchar('\n'); + prev = next; + } +} + +/* + * Dump TCP statistics structure. + */ +void +tcp_stats(off, name) + u_long off; + char *name; +{ + struct tcpstat tcpstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&tcpstat, sizeof (tcpstat)); + +#define p(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, plural(tcpstat.f)) +#define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \ + printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2)) +#define p3(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, plurales(tcpstat.f)) + + p(tcps_sndtotal, "\t%d packet%s sent\n"); + p2(tcps_sndpack,tcps_sndbyte, + "\t\t%d data packet%s (%d byte%s)\n"); + p2(tcps_sndrexmitpack, tcps_sndrexmitbyte, + "\t\t%d data packet%s (%d byte%s) retransmitted\n"); + p2(tcps_sndacks, tcps_delack, + "\t\t%d ack-only packet%s (%d delayed)\n"); + p(tcps_sndurg, "\t\t%d URG only packet%s\n"); + p(tcps_sndprobe, "\t\t%d window probe packet%s\n"); + p(tcps_sndwinup, "\t\t%d window update packet%s\n"); + p(tcps_sndctrl, "\t\t%d control packet%s\n"); + p(tcps_rcvtotal, "\t%d packet%s received\n"); + p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n"); + p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n"); + p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n"); + p2(tcps_rcvpack, tcps_rcvbyte, + "\t\t%d packet%s (%d byte%s) received in-sequence\n"); + p2(tcps_rcvduppack, tcps_rcvdupbyte, + "\t\t%d completely duplicate packet%s (%d byte%s)\n"); + p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n"); + p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte, + "\t\t%d packet%s with some dup. data (%d byte%s duped)\n"); + p2(tcps_rcvoopack, tcps_rcvoobyte, + "\t\t%d out-of-order packet%s (%d byte%s)\n"); + p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin, + "\t\t%d packet%s (%d byte%s) of data after window\n"); + p(tcps_rcvwinprobe, "\t\t%d window probe%s\n"); + p(tcps_rcvwinupd, "\t\t%d window update packet%s\n"); + p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n"); + p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n"); + p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n"); + p(tcps_rcvshort, "\t\t%d discarded because packet too short\n"); + p(tcps_connattempt, "\t%d connection request%s\n"); + p(tcps_accepts, "\t%d connection accept%s\n"); + p(tcps_connects, "\t%d connection%s established (including accepts)\n"); + p2(tcps_closed, tcps_drops, + "\t%d connection%s closed (including %d drop%s)\n"); + p(tcps_conndrops, "\t%d embryonic connection%s dropped\n"); + p2(tcps_rttupdated, tcps_segstimed, + "\t%d segment%s updated rtt (of %d attempt%s)\n"); + p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n"); + p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n"); + p(tcps_persisttimeo, "\t%d persist timeout%s\n"); + p(tcps_keeptimeo, "\t%d keepalive timeout%s\n"); + p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n"); + p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n"); + p(tcps_predack, "\t%d correct ACK header prediction%s\n"); + p(tcps_preddat, "\t%d correct data packet header prediction%s\n"); + p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n"); +#undef p +#undef p2 +#undef p3 +} + +/* + * Dump UDP statistics structure. + */ +void +udp_stats(off, name) + u_long off; + char *name; +{ + struct udpstat udpstat; + u_long delivered; + + if (off == 0) + return; + kread(off, (char *)&udpstat, sizeof (udpstat)); + printf("%s:\n", name); +#define p(f, m) if (udpstat.f || sflag <= 1) \ + printf(m, udpstat.f, plural(udpstat.f)) + p(udps_ipackets, "\t%u datagram%s received\n"); + p(udps_hdrops, "\t%u with incomplete header\n"); + p(udps_badlen, "\t%u with bad data length field\n"); + p(udps_badsum, "\t%u with bad checksum\n"); + p(udps_noport, "\t%u dropped due to no socket\n"); + p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n"); + p(udps_fullsock, "\t%u dropped due to full socket buffers\n"); + delivered = udpstat.udps_ipackets - + udpstat.udps_hdrops - + udpstat.udps_badlen - + udpstat.udps_badsum - + udpstat.udps_noport - + udpstat.udps_noportbcast - + udpstat.udps_fullsock; + if (delivered || sflag <= 1) + printf("\t%u delivered\n", delivered); + p(udps_opackets, "\t%u datagram%s output\n"); +#undef p +} + +/* + * Dump IP statistics structure. + */ +void +ip_stats(off, name) + u_long off; + char *name; +{ + struct ipstat ipstat; + + if (off == 0) + return; + kread(off, (char *)&ipstat, sizeof (ipstat)); + printf("%s:\n", name); + +#define p(f, m) if (ipstat.f || sflag <= 1) \ + printf(m, ipstat.f, plural(ipstat.f)) + + p(ips_total, "\t%u total packet%s received\n"); + p(ips_badsum, "\t%u bad header checksum%s\n"); + p(ips_toosmall, "\t%u with size smaller than minimum\n"); + p(ips_tooshort, "\t%u with data size < data length\n"); + p(ips_badhlen, "\t%u with header length < data size\n"); + p(ips_badlen, "\t%u with data length < header length\n"); + p(ips_badoptions, "\t%u with bad options\n"); + p(ips_badvers, "\t%u with incorrect version number\n"); + p(ips_fragments, "\t%u fragment%s received\n"); + p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n"); + p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n"); + p(ips_reassembled, "\t%u packet%s reassembled ok\n"); + p(ips_delivered, "\t%u packet%s for this host\n"); + p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n"); + p(ips_forward, "\t%u packet%s forwarded\n"); + p(ips_cantforward, "\t%u packet%s not forwardable\n"); + p(ips_redirectsent, "\t%u redirect%s sent\n"); + p(ips_localout, "\t%u packet%s sent from this host\n"); + p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n"); + p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n"); + p(ips_noroute, "\t%u output packet%s discarded due to no route\n"); + p(ips_fragmented, "\t%u output datagram%s fragmented\n"); + p(ips_ofragments, "\t%u fragment%s created\n"); + p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n"); +#undef p +} + +static char *icmpnames[] = { + "echo reply", + "#1", + "#2", + "destination unreachable", + "source quench", + "routing redirect", + "#6", + "#7", + "echo", + "#9", + "#10", + "time exceeded", + "parameter problem", + "time stamp", + "time stamp reply", + "information request", + "information request reply", + "address mask request", + "address mask reply", +}; + +/* + * Dump ICMP statistics. + */ +void +icmp_stats(off, name) + u_long off; + char *name; +{ + struct icmpstat icmpstat; + register int i, first; + + if (off == 0) + return; + kread(off, (char *)&icmpstat, sizeof (icmpstat)); + printf("%s:\n", name); + +#define p(f, m) if (icmpstat.f || sflag <= 1) \ + printf(m, icmpstat.f, plural(icmpstat.f)) + + p(icps_error, "\t%u call%s to icmp_error\n"); + p(icps_oldicmp, + "\t%u error%s not generated 'cuz old message was icmp\n"); + for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) + if (icmpstat.icps_outhist[i] != 0) { + if (first) { + printf("\tOutput histogram:\n"); + first = 0; + } + printf("\t\t%s: %u\n", icmpnames[i], + icmpstat.icps_outhist[i]); + } + p(icps_badcode, "\t%u message%s with bad code fields\n"); + p(icps_tooshort, "\t%u message%s < minimum length\n"); + p(icps_checksum, "\t%u bad checksum%s\n"); + p(icps_badlen, "\t%u message%s with bad length\n"); + for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) + if (icmpstat.icps_inhist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %u\n", icmpnames[i], + icmpstat.icps_inhist[i]); + } + p(icps_reflect, "\t%u message response%s generated\n"); +#undef p +} + +/* + * Dump IGMP statistics structure. + */ +void +igmp_stats(off, name) + u_long off; + char *name; +{ + struct igmpstat igmpstat; + + if (off == 0) + return; + kread(off, (char *)&igmpstat, sizeof (igmpstat)); + printf("%s:\n", name); + +#define p(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, igmpstat.f, plural(igmpstat.f)) +#define py(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y") + p(igps_rcv_total, "\t%u message%s received\n"); + p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n"); + p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n"); + py(igps_rcv_queries, "\t%u membership quer%s received\n"); + py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n"); + p(igps_rcv_reports, "\t%u membership report%s received\n"); + p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n"); + p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n"); + p(igps_snd_reports, "\t%u membership report%s sent\n"); +#undef p +#undef py +} + +/* + * Pretty print an Internet address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ +void +inetprint(in, port, proto) + register struct in_addr *in; + int port; + char *proto; +{ + struct servent *sp = 0; + char line[80], *cp; + int width; + + sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in)); + cp = index(line, '\0'); + if (!nflag && port) + sp = getservbyport((int)port, proto); + if (sp || port == 0) + sprintf(cp, "%.8s", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d", ntohs((u_short)port)); + width = Aflag ? 18 : 22; + printf(" %-*.*s", width, width, line); +} + +/* + * Construct an Internet address representation. + * If the nflag has been supplied, give + * numeric value, otherwise try for symbolic name. + */ +char * +inetname(inp) + struct in_addr *inp; +{ + register char *cp; + static char line[50]; + struct hostent *hp; + struct netent *np; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + + if (first && !nflag) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!nflag && inp->s_addr != INADDR_ANY) { + int net = inet_netof(*inp); + int lna = inet_lnaof(*inp); + + if (lna == INADDR_ANY) { + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp == 0) { + hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + } + if (inp->s_addr == INADDR_ANY) + strcpy(line, "*"); + else if (cp) + strcpy(line, cp); + else { + inp->s_addr = ntohl(inp->s_addr); +#define C(x) ((x) & 0xff) + sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24), + C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr)); + } + return (line); +} diff --git a/usr.bin/netstat/iso.c b/usr.bin/netstat/iso.c new file mode 100644 index 0000000..1eecf15 --- /dev/null +++ b/usr.bin/netstat/iso.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)iso.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * $Header: iso.c,v 1.5 92/06/04 00:36:32 leres Exp $ + * $Source: /usr/src/usr.bin/netstat/RCS/iso.c,v $ + */ +/******************************************************************************* + Copyright IBM Corporation 1987 + + All Rights Reserved + +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 appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +IBM 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. + +*******************************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef satosiso +#include +#include +#include +#include +#include +#include +#include +#ifdef IncStat +#undef IncStat +#endif +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +static void tprintstat __P((struct tp_stat *, int)); +static void isonetprint __P((struct sockaddr_iso *, int)); +static void hexprint __P((int, char *, char *)); +extern void inetprint __P((struct in_addr *, int, char *)); + +/* + * Dump esis stats + */ +void +esis_stats(off, name) + u_long off; + char *name; +{ + struct esis_stat esis_stat; + + if (off == 0 || + kread(off, (char *)&esis_stat, sizeof (struct esis_stat))) + return; + printf("%s:\n", name); + printf("\t%d esh sent, %d esh received\n", esis_stat.es_eshsent, + esis_stat.es_eshrcvd); + printf("\t%d ish sent, %d ish received\n", esis_stat.es_ishsent, + esis_stat.es_ishrcvd); + printf("\t%d rd sent, %d rd received\n", esis_stat.es_rdsent, + esis_stat.es_rdrcvd); + printf("\t%d pdus not sent due to insufficient memory\n", + esis_stat.es_nomem); + printf("\t%d pdus received with bad checksum\n", esis_stat.es_badcsum); + printf("\t%d pdus received with bad version number\n", + esis_stat.es_badvers); + printf("\t%d pdus received with bad type field\n", esis_stat.es_badtype); + printf("\t%d short pdus received\n", esis_stat.es_toosmall); +} + +/* + * Dump clnp statistics structure. + */ +void +clnp_stats(off, name) + u_long off; + char *name; +{ + struct clnp_stat clnp_stat; + + if (off == 0 || + kread(off, (char *)&clnp_stat, sizeof (clnp_stat))) + return; + + printf("%s:\n\t%d total packets sent\n", name, clnp_stat.cns_sent); + printf("\t%d total fragments sent\n", clnp_stat.cns_fragments); + printf("\t%d total packets received\n", clnp_stat.cns_total); + printf("\t%d with fixed part of header too small\n", + clnp_stat.cns_toosmall); + printf("\t%d with header length not reasonable\n", clnp_stat.cns_badhlen); + printf("\t%d incorrect checksum%s\n", + clnp_stat.cns_badcsum, plural(clnp_stat.cns_badcsum)); + printf("\t%d with unreasonable address lengths\n", clnp_stat.cns_badaddr); + printf("\t%d with forgotten segmentation information\n", + clnp_stat.cns_noseg); + printf("\t%d with an incorrect protocol identifier\n", clnp_stat.cns_noproto); + printf("\t%d with an incorrect version\n", clnp_stat.cns_badvers); + printf("\t%d dropped because the ttl has expired\n", + clnp_stat.cns_ttlexpired); + printf("\t%d clnp cache misses\n", clnp_stat.cns_cachemiss); + printf("\t%d clnp congestion experience bits set\n", + clnp_stat.cns_congest_set); + printf("\t%d clnp congestion experience bits received\n", + clnp_stat.cns_congest_rcvd); +} +/* + * Dump CLTP statistics structure. + */ +void +cltp_stats(off, name) + u_long off; + char *name; +{ + struct cltpstat cltpstat; + + if (off == 0 || + kread(off, (char *)&cltpstat, sizeof (cltpstat))) + return; + printf("%s:\n\t%u incomplete header%s\n", name, + cltpstat.cltps_hdrops, plural(cltpstat.cltps_hdrops)); + printf("\t%u bad data length field%s\n", + cltpstat.cltps_badlen, plural(cltpstat.cltps_badlen)); + printf("\t%u bad checksum%s\n", + cltpstat.cltps_badsum, plural(cltpstat.cltps_badsum)); +} + +struct tp_pcb tpcb; +struct isopcb isopcb; +struct socket sockb; +union { + struct sockaddr_iso siso; + char data[128]; +} laddr, faddr; +#define kget(o, p) \ + (kread((u_long)(o), (char *)&p, sizeof (p))) + +static int first = 1; + +/* + * Print a summary of connections related to an Internet + * protocol. For TP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ +void +iso_protopr(off, name) + u_long off; + char *name; +{ + struct isopcb cb; + register struct isopcb *prev, *next; + + if (off == 0) { + printf("%s control block: symbol not in namelist\n", name); + return; + } + if (strcmp(name, "tp") == 0) { + tp_protopr(off, name); + return; + } + if (kread(off, (char *)&cb, sizeof(cb))) + return; + isopcb = cb; + prev = (struct isopcb *)off; + if (isopcb.isop_next == (struct isopcb *)off) + return; + while (isopcb.isop_next != (struct isopcb *)off) { + next = isopcb.isop_next; + kget(next, isopcb); + if (isopcb.isop_prev != prev) { + printf("prev 0x%x next 0x%x isop_prev 0x%x isop_next 0x%x???\n", + prev, next, isopcb.isop_prev, isopcb.isop_next); + break; + } + kget(isopcb.isop_socket, sockb); + iso_protopr1((u_long)next, 0); + putchar('\n'); + prev = next; + } +} + +void +iso_protopr1(kern_addr, istp) + u_long kern_addr; + int istp; +{ + if (first) { + printf("Active ISO net connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + if (Aflag) + printf("%8x ", + (sockb.so_pcb ? (void *)sockb.so_pcb : (void *)kern_addr)); + printf("%-5.5s %6d %6d ", "tp", sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + if (istp && tpcb.tp_lsuffixlen) { + hexprint(tpcb.tp_lsuffixlen, tpcb.tp_lsuffix, "()"); + printf("\t"); + } else if (isopcb.isop_laddr == 0) + printf("*.*\t"); + else { + if ((char *)isopcb.isop_laddr == ((char *)kern_addr) + + _offsetof(struct isopcb, isop_sladdr)) + laddr.siso = isopcb.isop_sladdr; + else + kget(isopcb.isop_laddr, laddr); + isonetprint((struct sockaddr_iso *)&laddr, 1); + } + if (istp && tpcb.tp_fsuffixlen) { + hexprint(tpcb.tp_fsuffixlen, tpcb.tp_fsuffix, "()"); + printf("\t"); + } else if (isopcb.isop_faddr == 0) + printf("*.*\t"); + else { + if ((char *)isopcb.isop_faddr == ((char *)kern_addr) + + _offsetof(struct isopcb, isop_sfaddr)) + faddr.siso = isopcb.isop_sfaddr; + else + kget(isopcb.isop_faddr, faddr); + isonetprint((struct sockaddr_iso *)&faddr, 0); + } +} + +void +tp_protopr(off, name) + u_long off; + char *name; +{ + extern char *tp_sstring[]; + struct tp_ref *tpr, *tpr_base; + struct tp_refinfo tpkerninfo; + int size; + + kget(off, tpkerninfo); + size = tpkerninfo.tpr_size * sizeof (*tpr); + tpr_base = (struct tp_ref *)malloc(size); + if (tpr_base == 0) + return; + kread((u_long)(tpkerninfo.tpr_base), (char *)tpr_base, size); + for (tpr = tpr_base; tpr < tpr_base + tpkerninfo.tpr_size; tpr++) { + if (tpr->tpr_pcb == 0) + continue; + kget(tpr->tpr_pcb, tpcb); + if (tpcb.tp_state == ST_ERROR) + printf("undefined tpcb state: 0x%x\n", tpr->tpr_pcb); + if (!aflag && + (tpcb.tp_state == TP_LISTENING || + tpcb.tp_state == TP_CLOSED || + tpcb.tp_state == TP_REFWAIT)) { + continue; + } + kget(tpcb.tp_sock, sockb); + if (tpcb.tp_npcb) switch(tpcb.tp_netservice) { + case IN_CLNS: + tp_inproto((u_long)tpkerninfo.tpr_base); + break; + default: + kget(tpcb.tp_npcb, isopcb); + iso_protopr1((u_long)tpcb.tp_npcb, 1); + break; + } + if (tpcb.tp_state >= tp_NSTATES) + printf(" %d", tpcb.tp_state); + else + printf(" %-12.12s", tp_sstring[tpcb.tp_state]); + putchar('\n'); + } +} + +void +tp_inproto(pcb) + u_long pcb; +{ + struct inpcb inpcb; + kget(tpcb.tp_npcb, inpcb); + if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) + return; + if (Aflag) + printf("%8x ", pcb); + printf("%-5.5s %6d %6d ", "tpip", + sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + inetprint(&inpcb.inp_laddr, inpcb.inp_lport, "tp"); + inetprint(&inpcb.inp_faddr, inpcb.inp_fport, "tp"); +} + +/* + * Pretty print an iso address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ + +#ifdef notdef +char * +isonetname(iso) + register struct iso_addr *iso; +{ + struct sockaddr_iso sa; + struct iso_hostent *ihe = 0; + struct iso_hostent *iso_gethostentrybyaddr(); + struct iso_hostent *iso_getserventrybytsel(); + struct iso_hostent Ihe; + static char line[80]; + + bzero(line, sizeof(line)); + if( iso->isoa_afi ) { + sa.siso_family = AF_ISO; + sa.siso_addr = *iso; + sa.siso_tsuffix = 0; + + if (!nflag ) + ihe = iso_gethostentrybyaddr( &sa, 0, 0 ); + if( ihe ) { + Ihe = *ihe; + ihe = &Ihe; + sprintf(line, "%s", ihe->isoh_hname); + } else { + sprintf(line, "%s", iso_ntoa(iso)); + } + } else { + sprintf(line, "*"); + } + return line; +} + +static void +isonetprint(iso, sufx, sufxlen, islocal) + register struct iso_addr *iso; + char *sufx; + u_short sufxlen; + int islocal; +{ + struct iso_hostent *iso_getserventrybytsel(), *ihe; + struct iso_hostent Ihe; + char *line, *cp; + int Alen = Aflag?18:22; + + line = isonetname(iso); + cp = index(line, '\0'); + ihe = (struct iso_hostent *)0; + + if( islocal ) + islocal = 20; + else + islocal = 22 + Alen; + + if(Aflag) + islocal += 10 ; + + if(!nflag) { + if( (cp -line)>10 ) { + cp = line+10; + bzero(cp, sizeof(line)-10); + } + } + + *cp++ = '.'; + if(sufxlen) { + if( !Aflag && !nflag && (ihe=iso_getserventrybytsel(sufx, sufxlen))) { + Ihe = *ihe; + ihe = &Ihe; + } + if( ihe && (strlen(ihe->isoh_aname)>0) ) { + sprintf(cp, "%s", ihe->isoh_aname); + } else { + iso_sprinttsel(cp, sufx, sufxlen); + } + } else + sprintf(cp, "*"); + /* + fprintf(stdout, Aflag?" %-18.18s":" %-22.22s", line); + */ + + if( strlen(line) > Alen ) { + fprintf(stdout, " %s", line); + fprintf(stdout, "\n %*.s", islocal+Alen," "); + } else { + fprintf(stdout, " %-*.*s", Alen, Alen,line); + } +} +#endif + +#ifdef notdef +static void +x25_protopr(off, name) + u_long off; + char *name; +{ + static char *xpcb_states[] = { + "CLOSED", + "LISTENING", + "CLOSING", + "CONNECTING", + "ACKWAIT", + "OPEN", + }; + register struct isopcb *prev, *next; + struct x25_pcb xpcb; + + if (off == 0) { + printf("%s control block: symbol not in namelist\n", name); + return; + } + kread(off, &xpcb, sizeof (struct x25_pcb)); + prev = (struct isopcb *)off; + if (xpcb.x_next == (struct isopcb *)off) + return; + while (xpcb.x_next != (struct isopcb *)off) { + next = isopcb.isop_next; + kread((u_long)next, &xpcb, sizeof (struct x25_pcb)); + if (xpcb.x_prev != prev) { + printf("???\n"); + break; + } + kread((u_long)xpcb.x_socket, &sockb, sizeof (sockb)); + + if (!aflag && + xpcb.x_state == LISTENING || + xpcb.x_state == TP_CLOSED ) { + prev = next; + continue; + } + if (first) { + printf("Active X25 net connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + isonetprint(&xpcb.x_laddr.siso_addr, &xpcb.x_lport, + sizeof(xpcb.x_lport), 1); + isonetprint(&xpcb.x_faddr.siso_addr, &xpcb.x_fport, + sizeof(xpcb.x_lport), 0); + if (xpcb.x_state < 0 || xpcb.x_state >= x25_NSTATES) + printf(" 0x0x0x0x0x0x0x0x0x%x", xpcb.x_state); + else + printf(" %-12.12s", xpcb_states[xpcb.x_state]); + putchar('\n'); + prev = next; + } +} +#endif + +struct tp_stat tp_stat; + +void +tp_stats(off, name) + caddr_t off, name; +{ + if (off == 0) { + printf("TP not configured\n\n"); + return; + } + printf("%s:\n", name); + kget(off, tp_stat); + tprintstat(&tp_stat, 8); +} + +#define OUT stdout + +static void +tprintstat(s, indent) + register struct tp_stat *s; + int indent; +{ + fprintf(OUT, + "%*sReceiving:\n",indent," "); + fprintf(OUT, + "\t%*s%d variable parameter%s ignored\n", indent," ", + s->ts_param_ignored ,plural(s->ts_param_ignored)); + fprintf(OUT, + "\t%*s%d invalid parameter code%s\n", indent, " ", + s->ts_inv_pcode ,plural(s->ts_inv_pcode)); + fprintf(OUT, + "\t%*s%d invalid parameter value%s\n", indent, " ", + s->ts_inv_pval ,plural(s->ts_inv_pval)); + fprintf(OUT, + "\t%*s%d invalid dutype%s\n", indent, " ", + s->ts_inv_dutype ,plural(s->ts_inv_dutype)); + fprintf(OUT, + "\t%*s%d negotiation failure%s\n", indent, " ", + s->ts_negotfailed ,plural(s->ts_negotfailed)); + fprintf(OUT, + "\t%*s%d invalid destination reference%s\n", indent, " ", + s->ts_inv_dref ,plural(s->ts_inv_dref)); + fprintf(OUT, + "\t%*s%d invalid suffix parameter%s\n", indent, " ", + s->ts_inv_sufx ,plural(s->ts_inv_sufx)); + fprintf(OUT, + "\t%*s%d invalid length\n",indent, " ", s->ts_inv_length); + fprintf(OUT, + "\t%*s%d invalid checksum%s\n", indent, " ", + s->ts_bad_csum ,plural(s->ts_bad_csum)); + fprintf(OUT, + "\t%*s%d DT%s out of order\n", indent, " ", + s->ts_dt_ooo ,plural(s->ts_dt_ooo)); + fprintf(OUT, + "\t%*s%d DT%s not in window\n", indent, " ", + s->ts_dt_niw ,plural(s->ts_dt_niw)); + fprintf(OUT, + "\t%*s%d duplicate DT%s\n", indent, " ", + s->ts_dt_dup ,plural(s->ts_dt_dup)); + fprintf(OUT, + "\t%*s%d XPD%s not in window\n", indent, " ", + s->ts_xpd_niw ,plural(s->ts_xpd_niw)); + fprintf(OUT, + "\t%*s%d XPD%s w/o credit to stash\n", indent, " ", + s->ts_xpd_dup ,plural(s->ts_xpd_dup)); + fprintf(OUT, + "\t%*s%d time%s local credit reneged\n", indent, " ", + s->ts_lcdt_reduced ,plural(s->ts_lcdt_reduced)); + fprintf(OUT, + "\t%*s%d concatenated TPDU%s\n", indent, " ", + s->ts_concat_rcvd ,plural(s->ts_concat_rcvd)); + fprintf(OUT, + "%*sSending:\n", indent, " "); + fprintf(OUT, + "\t%*s%d XPD mark%s discarded\n", indent, " ", + s->ts_xpdmark_del ,plural(s->ts_xpdmark_del)); + fprintf(OUT, + "\t%*sXPD stopped data flow %d time%s\n", indent, " ", + s->ts_xpd_intheway ,plural(s->ts_xpd_intheway)); + fprintf(OUT, + "\t%*s%d time%s foreign window closed\n", indent, " ", + s->ts_zfcdt ,plural(s->ts_zfcdt)); + fprintf(OUT, + "%*sMiscellaneous:\n", indent, " "); + fprintf(OUT, + "\t%*s%d small mbuf%s\n", indent, " ", + s->ts_mb_small ,plural(s->ts_mb_small)); + fprintf(OUT, + "\t%*s%d cluster%s\n", indent, " ", + s->ts_mb_cluster, plural(s->ts_mb_cluster)); + fprintf(OUT, + "\t%*s%d source quench \n",indent, " ", + s->ts_quench); + fprintf(OUT, + "\t%*s%d dec bit%s\n", indent, " ", + s->ts_rcvdecbit, plural(s->ts_rcvdecbit)); + fprintf(OUT, + "\t%*sM:L ( M mbuf chains of length L)\n", indent, " "); + { + register int j; + + fprintf(OUT, "\t%*s%d: over 16\n", indent, " ", + s->ts_mb_len_distr[0]); + for( j=1; j<=8; j++) { + fprintf(OUT, + "\t%*s%d: %d\t\t%d: %d\n", indent, " ", + s->ts_mb_len_distr[j],j, + s->ts_mb_len_distr[j<<1],j<<1 + ); + } + } + fprintf(OUT, + "\t%*s%d EOT rcvd\n", indent, " ", s->ts_eot_input); + fprintf(OUT, + "\t%*s%d EOT sent\n", indent, " ", s->ts_EOT_sent); + fprintf(OUT, + "\t%*s%d EOT indication%s\n", indent, " ", + s->ts_eot_user ,plural(s->ts_eot_user)); + + fprintf(OUT, + "%*sConnections:\n", indent, " "); + fprintf(OUT, + "\t%*s%d connection%s used extended format\n", indent, " ", + s->ts_xtd_fmt ,plural(s->ts_xtd_fmt)); + fprintf(OUT, + "\t%*s%d connection%s allowed transport expedited data\n", indent, " ", + s->ts_use_txpd ,plural(s->ts_use_txpd)); + fprintf(OUT, + "\t%*s%d connection%s turned off checksumming\n", indent, " ", + s->ts_csum_off ,plural(s->ts_csum_off)); + fprintf(OUT, + "\t%*s%d connection%s dropped due to retrans limit\n", indent, " ", + s->ts_conn_gaveup ,plural(s->ts_conn_gaveup)); + fprintf(OUT, + "\t%*s%d tp 4 connection%s\n", indent, " ", + s->ts_tp4_conn ,plural(s->ts_tp4_conn)); + fprintf(OUT, + "\t%*s%d tp 0 connection%s\n", indent, " ", + s->ts_tp0_conn ,plural(s->ts_tp0_conn)); + { + register int j; + static char *name[]= { + "~LOCAL, PDN", + "~LOCAL,~PDN", + " LOCAL,~PDN", + " LOCAL, PDN" + }; + + fprintf(OUT, + "\n%*sRound trip times, listed in ticks:\n", indent, " "); + fprintf(OUT, + "\t%*s%11.11s %12.12s | %12.12s | %s\n", indent, " ", + "Category", + "Smoothed avg", "Deviation", "Deviation/Avg"); + for (j = 0; j <= 3; j++) { + fprintf(OUT, + "\t%*s%11.11s: %-11d | %-11d | %-11d | %-11d\n", indent, " ", + name[j], + s->ts_rtt[j], + s->ts_rtt[j], + s->ts_rtv[j], + s->ts_rtv[j]); + } + } + fprintf(OUT, +"\n%*sTpdus RECVD [%d valid, %3.6f %% of total (%d); %d dropped]\n",indent," ", + s->ts_tpdu_rcvd , + ((s->ts_pkt_rcvd > 0) ? + ((100 * (float)s->ts_tpdu_rcvd)/(float)s->ts_pkt_rcvd) + : 0), + s->ts_pkt_rcvd, + s->ts_recv_drop ); + + fprintf(OUT, + "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", + s->ts_DT_rcvd, s->ts_AK_rcvd, s->ts_DR_rcvd, s->ts_CR_rcvd); + fprintf(OUT, + "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", + s->ts_XPD_rcvd, s->ts_XAK_rcvd, s->ts_DC_rcvd, s->ts_CC_rcvd, + s->ts_ER_rcvd); + fprintf(OUT, + "\n%*sTpdus SENT [%d total, %d dropped]\n", indent, " ", + s->ts_tpdu_sent, s->ts_send_drop); + + fprintf(OUT, + "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", + s->ts_DT_sent, s->ts_AK_sent, s->ts_DR_sent, s->ts_CR_sent); + fprintf(OUT, + "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", + s->ts_XPD_sent, s->ts_XAK_sent, s->ts_DC_sent, s->ts_CC_sent, + s->ts_ER_sent); + + fprintf(OUT, + "\n%*sRetransmissions:\n", indent, " "); +#define PERCENT(X,Y) (((Y)>0)?((100 *(float)(X)) / (float) (Y)):0) + + fprintf(OUT, + "\t%*sCR %6d CC %6d DR %6d \n", indent, " ", + s->ts_retrans_cr, s->ts_retrans_cc, s->ts_retrans_dr); + fprintf(OUT, + "\t%*sDT %6d (%5.2f%%)\n", indent, " ", + s->ts_retrans_dt, + PERCENT(s->ts_retrans_dt, s->ts_DT_sent)); + fprintf(OUT, + "\t%*sXPD %6d (%5.2f%%)\n", indent, " ", + s->ts_retrans_xpd, + PERCENT(s->ts_retrans_xpd, s->ts_XPD_sent)); + + + fprintf(OUT, + "\n%*sE Timers: [%6d ticks]\n", indent, " ", s->ts_Eticks); + fprintf(OUT, + "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",indent, " ", + s->ts_Eset ,plural(s->ts_Eset), + s->ts_Eexpired ,plural(s->ts_Eexpired), + s->ts_Ecan_act ,plural(s->ts_Ecan_act)); + + fprintf(OUT, + "\n%*sC Timers: [%6d ticks]\n", indent, " ",s->ts_Cticks); + fprintf(OUT, + "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n", + indent, " ", + s->ts_Cset ,plural(s->ts_Cset), + s->ts_Cexpired ,plural(s->ts_Cexpired), + s->ts_Ccan_act ,plural(s->ts_Ccan_act)); + fprintf(OUT, + "%*s%6d inactive timer%s cancelled\n", indent, " ", + s->ts_Ccan_inact ,plural(s->ts_Ccan_inact)); + + fprintf(OUT, + "\n%*sPathological debugging activity:\n", indent, " "); + fprintf(OUT, + "\t%*s%6d CC%s sent to zero dref\n", indent, " ", + s->ts_zdebug ,plural(s->ts_zdebug)); + /* SAME LINE AS ABOVE */ + fprintf(OUT, + "\t%*s%6d random DT%s dropped\n", indent, " ", + s->ts_ydebug ,plural(s->ts_ydebug)); + fprintf(OUT, + "\t%*s%6d illegally large XPD TPDU%s\n", indent, " ", + s->ts_vdebug ,plural(s->ts_vdebug)); + fprintf(OUT, + "\t%*s%6d faked reneging of cdt\n", indent, " ", + s->ts_ldebug ); + + fprintf(OUT, + "\n%*sACK reasons:\n", indent, " "); + fprintf(OUT, "\t%*s%6d not acked immediately\n", indent, " ", + s->ts_ackreason[_ACK_DONT_] ); + fprintf(OUT, "\t%*s%6d strategy==each\n", indent, " ", + s->ts_ackreason[_ACK_STRAT_EACH_] ); + fprintf(OUT, "\t%*s%6d strategy==fullwindow\n", indent, " ", + s->ts_ackreason[_ACK_STRAT_FULLWIN_] ); + fprintf(OUT, "\t%*s%6d duplicate DT\n", indent, " ", + s->ts_ackreason[_ACK_DUP_] ); + fprintf(OUT, "\t%*s%6d EOTSDU\n", indent, " ", + s->ts_ackreason[_ACK_EOT_] ); + fprintf(OUT, "\t%*s%6d reordered DT\n", indent, " ", + s->ts_ackreason[_ACK_REORDER_] ); + fprintf(OUT, "\t%*s%6d user rcvd\n", indent, " ", + s->ts_ackreason[_ACK_USRRCV_] ); + fprintf(OUT, "\t%*s%6d fcc reqd\n", indent, " ", + s->ts_ackreason[_ACK_FCC_] ); +} +#ifndef SSEL +#define SSEL(s) ((s)->siso_tlen + TSEL(s)) +#define PSEL(s) ((s)->siso_slen + SSEL(s)) +#endif + +static void +isonetprint(siso, islocal) + register struct sockaddr_iso *siso; + int islocal; +{ + hexprint(siso->siso_nlen, siso->siso_addr.isoa_genaddr, "{}"); + if (siso->siso_tlen || siso->siso_slen || siso->siso_plen) + hexprint(siso->siso_tlen, TSEL(siso), "()"); + if (siso->siso_slen || siso->siso_plen) + hexprint(siso->siso_slen, SSEL(siso), "[]"); + if (siso->siso_plen) + hexprint(siso->siso_plen, PSEL(siso), "<>"); + putchar(' '); +} + +static char hexlist[] = "0123456789abcdef", obuf[128]; + +static void +hexprint(n, buf, delim) + int n; + char *buf, *delim; +{ + register u_char *in = (u_char *)buf, *top = in + n; + register char *out = obuf; + register int i; + + if (n == 0) + return; + while (in < top) { + i = *in++; + *out++ = '.'; + if (i > 0xf) { + out[1] = hexlist[i & 0xf]; + i >>= 4; + out[0] = hexlist[i]; + out += 2; + } else + *out++ = hexlist[i]; + } + *obuf = *delim; *out++ = delim[1]; *out = 0; + printf("%s", obuf); +} diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c new file mode 100644 index 0000000..6d30186 --- /dev/null +++ b/usr.bin/netstat/main.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 1983, 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1983, 1988, 1993\n\ + Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netstat.h" + +struct nlist nl[] = { +#define N_MBSTAT 0 + { "_mbstat" }, +#define N_IPSTAT 1 + { "_ipstat" }, +#define N_TCB 2 + { "_tcb" }, +#define N_TCPSTAT 3 + { "_tcpstat" }, +#define N_UDB 4 + { "_udb" }, +#define N_UDPSTAT 5 + { "_udpstat" }, +#define N_IFNET 6 + { "_ifnet" }, +#define N_IMP 7 + { "_imp_softc" }, +#define N_ICMPSTAT 8 + { "_icmpstat" }, +#define N_RTSTAT 9 + { "_rtstat" }, +#define N_UNIXSW 10 + { "_unixsw" }, +#define N_IDP 11 + { "_nspcb"}, +#define N_IDPSTAT 12 + { "_idpstat"}, +#define N_SPPSTAT 13 + { "_spp_istat"}, +#define N_NSERR 14 + { "_ns_errstat"}, +#define N_CLNPSTAT 15 + { "_clnp_stat"}, +#define IN_NOTUSED 16 + { "_tp_inpcb" }, +#define ISO_TP 17 + { "_tp_refinfo" }, +#define N_TPSTAT 18 + { "_tp_stat" }, +#define N_ESISSTAT 19 + { "_esis_stat"}, +#define N_NIMP 20 + { "_nimp"}, +#define N_RTREE 21 + { "_rt_tables"}, +#define N_CLTP 22 + { "_cltb"}, +#define N_CLTPSTAT 23 + { "_cltpstat"}, +#define N_NFILE 24 + { "_nfile" }, +#define N_FILE 25 + { "_file" }, +#define N_IGMPSTAT 26 + { "_igmpstat" }, +#define N_MRTPROTO 27 + { "_ip_mrtproto" }, +#define N_MRTSTAT 28 + { "_mrtstat" }, +#define N_MRTTABLE 29 + { "_mrttable" }, +#define N_VIFTABLE 30 + { "_viftable" }, + "", +}; + +struct protox { + u_char pr_index; /* index into nlist of cb head */ + u_char pr_sindex; /* index into nlist of stat block */ + u_char pr_wanted; /* 1 if wanted, 0 otherwise */ + void (*pr_cblocks)(); /* control blocks printing routine */ + void (*pr_stats)(); /* statistics printing routine */ + char *pr_name; /* well-known name */ +} protox[] = { + { N_TCB, N_TCPSTAT, 1, protopr, + tcp_stats, "tcp" }, + { N_UDB, N_UDPSTAT, 1, protopr, + udp_stats, "udp" }, + { -1, N_IPSTAT, 1, 0, + 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 } +}; + +struct protox nsprotox[] = { + { N_IDP, N_IDPSTAT, 1, nsprotopr, + idp_stats, "idp" }, + { N_IDP, N_SPPSTAT, 1, nsprotopr, + spp_stats, "spp" }, + { -1, N_NSERR, 1, 0, + nserr_stats, "ns_err" }, + { -1, -1, 0, 0, + 0, 0 } +}; + +struct protox isoprotox[] = { + { ISO_TP, N_TPSTAT, 1, iso_protopr, + tp_stats, "tp" }, + { N_CLTP, N_CLTPSTAT, 1, iso_protopr, + cltp_stats, "cltp" }, + { -1, N_CLNPSTAT, 1, 0, + clnp_stats, "clnp"}, + { -1, N_ESISSTAT, 1, 0, + esis_stats, "esis"}, + { -1, -1, 0, 0, + 0, 0 } +}; + +struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL }; + +static void printproto __P((struct protox *, char *)); +static void usage __P((void)); +static struct protox *name2protox __P((char *)); +static struct protox *knownname __P((char *)); + +kvm_t *kvmd; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + register struct protoent *p; + register struct protox *tp; /* for printing cblocks & stats */ + register char *cp; + int ch; + char *nlistf = NULL, *memf = NULL; + char buf[_POSIX2_LINE_MAX]; + + if (cp = rindex(argv[0], '/')) + prog = cp + 1; + else + prog = argv[0]; + af = AF_UNSPEC; + + while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) + switch(ch) { + case 'A': + Aflag = 1; + break; + case 'a': + aflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'f': + if (strcmp(optarg, "ns") == 0) + af = AF_NS; + else if (strcmp(optarg, "inet") == 0) + af = AF_INET; + else if (strcmp(optarg, "unix") == 0) + af = AF_UNIX; + else if (strcmp(optarg, "iso") == 0) + af = AF_ISO; + else { + (void)fprintf(stderr, + "%s: %s: unknown address family\n", + prog, optarg); + exit(1); + } + break; + case 'g': + gflag = 1; + break; + case 'I': { + char *cp; + + iflag = 1; + for (cp = interface = optarg; isalpha(*cp); cp++) + continue; + unit = atoi(cp); + *cp = '\0'; + break; + } + case 'i': + iflag = 1; + break; + case 'M': + memf = optarg; + break; + case 'm': + mflag = 1; + break; + case 'N': + nlistf = optarg; + break; + case 'n': + nflag = 1; + break; + case 'p': + if ((tp = name2protox(optarg)) == NULL) { + (void)fprintf(stderr, + "%s: %s: unknown or uninstrumented protocol\n", + prog, optarg); + exit(1); + } + pflag = 1; + break; + case 'r': + rflag = 1; + break; + case 's': + ++sflag; + break; + case 't': + tflag = 1; + break; + case 'u': + af = AF_UNIX; + break; + case 'w': + interval = atoi(optarg); + iflag = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + if (isdigit(**argv)) { + interval = atoi(*argv); + if (interval <= 0) + usage(); + ++argv; + iflag = 1; + } + if (*argv) { + nlistf = *argv; + if (*++argv) + memf = *argv; + } + } +#endif + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) { + fprintf(stderr, "%s: kvm_open: %s\n", prog, buf); + exit(1); + } + if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { + if (nlistf) + fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf); + else + fprintf(stderr, "%s: no namelist\n", prog); + exit(1); + } + if (mflag) { + mbpr(nl[N_MBSTAT].n_value); + exit(0); + } + if (pflag) { + if (tp->pr_stats) + (*tp->pr_stats)(nl[tp->pr_sindex].n_value, + tp->pr_name); + else + printf("%s: no stats routine\n", tp->pr_name); + exit(0); + } + /* + * Keep file descriptors open to avoid overhead + * of open/close on each call to get* routines. + */ + sethostent(1); + setnetent(1); + if (iflag) { + intpr(interval, nl[N_IFNET].n_value); + exit(0); + } + if (rflag) { + if (sflag) + rt_stats(nl[N_RTSTAT].n_value); + else + routepr(nl[N_RTREE].n_value); + exit(0); + } + if (gflag) { + if (sflag) + mrt_stats(nl[N_MRTPROTO].n_value, + nl[N_MRTSTAT].n_value); + else + mroutepr(nl[N_MRTPROTO].n_value, + nl[N_MRTTABLE].n_value, + nl[N_VIFTABLE].n_value); + exit(0); + } + if (af == AF_INET || af == AF_UNSPEC) { + setprotoent(1); + setservent(1); + /* ugh, this is O(MN) ... why do we do this? */ + while (p = getprotoent()) { + for (tp = protox; tp->pr_name; tp++) + if (strcmp(tp->pr_name, p->p_name) == 0) + break; + if (tp->pr_name == 0 || tp->pr_wanted == 0) + continue; + printproto(tp, p->p_name); + } + endprotoent(); + } + if (af == AF_NS || af == AF_UNSPEC) + for (tp = nsprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); + if (af == AF_ISO || af == AF_UNSPEC) + for (tp = isoprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); + if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) + unixpr(nl[N_UNIXSW].n_value); + exit(0); +} + +/* + * Print out protocol statistics or control blocks (per sflag). + * If the interface was not specifically requested, and the symbol + * is not in the namelist, ignore this one. + */ +static void +printproto(tp, name) + register struct protox *tp; + char *name; +{ + void (*pr)(); + u_long off; + + if (sflag) { + pr = tp->pr_stats; + off = nl[tp->pr_sindex].n_value; + } else { + pr = tp->pr_cblocks; + off = nl[tp->pr_index].n_value; + } + if (pr != NULL && (off || af != AF_UNSPEC)) + (*pr)(off, name); +} + +/* + * Read kernel memory, return 0 on success. + */ +int +kread(addr, buf, size) + u_long addr; + char *buf; + int size; +{ + + if (kvm_read(kvmd, addr, buf, size) != size) { + /* XXX this duplicates kvm_read's error printout */ + (void)fprintf(stderr, "%s: kvm_read %s\n", prog, + kvm_geterr(kvmd)); + return (-1); + } + return (0); +} + +char * +plural(n) + int n; +{ + return (n != 1 ? "s" : ""); +} + +char * +plurales(n) + int n; +{ + return (n != 1 ? "es" : ""); +} + +/* + * Find the protox for the given "well-known" name. + */ +static struct protox * +knownname(name) + char *name; +{ + struct protox **tpp, *tp; + + for (tpp = protoprotox; *tpp; tpp++) + for (tp = *tpp; tp->pr_name; tp++) + if (strcmp(tp->pr_name, name) == 0) + return (tp); + return (NULL); +} + +/* + * Find the protox corresponding to name. + */ +static struct protox * +name2protox(name) + char *name; +{ + struct protox *tp; + char **alias; /* alias from p->aliases */ + struct protoent *p; + + /* + * Try to find the name in the list of "well-known" names. If that + * fails, check if name is an alias for an Internet protocol. + */ + if (tp = knownname(name)) + return (tp); + + setprotoent(1); /* make protocol lookup cheaper */ + while (p = getprotoent()) { + /* assert: name not same as p->name */ + for (alias = p->p_aliases; *alias; alias++) + if (strcmp(name, *alias) == 0) { + endprotoent(); + return (knownname(p->p_name)); + } + } + endprotoent(); + return (NULL); +} + +static void +usage() +{ + (void)fprintf(stderr, +"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); + (void)fprintf(stderr, +" %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog); + (void)fprintf(stderr, +" %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog); + (void)fprintf(stderr, +" %s [-M core] [-N system] [-p protocol]\n", prog); + exit(1); +} diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c new file mode 100644 index 0000000..dd60a0e --- /dev/null +++ b/usr.bin/netstat/mbuf.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include "netstat.h" + +#define YES 1 +typedef int bool; + +struct mbstat mbstat; + +static struct mbtypes { + int mt_type; + char *mt_name; +} mbtypes[] = { + { MT_DATA, "data" }, + { MT_OOBDATA, "oob data" }, + { MT_CONTROL, "ancillary data" }, + { MT_HEADER, "packet headers" }, + { MT_SOCKET, "socket structures" }, /* XXX */ + { MT_PCB, "protocol control blocks" }, /* XXX */ + { MT_RTABLE, "routing table entries" }, /* XXX */ + { MT_HTABLE, "IMP host table entries" }, /* XXX */ + { MT_ATABLE, "address resolution tables" }, + { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ + { MT_SONAME, "socket names and addresses" }, + { MT_SOOPTS, "socket options" }, + { MT_RIGHTS, "access rights" }, + { MT_IFADDR, "interface addresses" }, /* XXX */ + { 0, 0 } +}; + +int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short); +bool seen[256]; /* "have we seen this type yet?" */ + +/* + * Print mbuf statistics. + */ +void +mbpr(mbaddr) + u_long mbaddr; +{ + register int totmem, totfree, totmbufs; + register int i; + register struct mbtypes *mp; + + if (nmbtypes != 256) { + fprintf(stderr, + "%s: unexpected change to mbstat; check source\n", prog); + return; + } + if (mbaddr == 0) { + fprintf(stderr, "%s: mbstat: symbol not in namelist\n", prog); + return; + } + if (kread(mbaddr, (char *)&mbstat, sizeof (mbstat))) + return; + totmbufs = 0; + for (mp = mbtypes; mp->mt_name; mp++) + totmbufs += mbstat.m_mtypes[mp->mt_type]; + printf("%u mbufs in use:\n", totmbufs); + for (mp = mbtypes; mp->mt_name; mp++) + if (mbstat.m_mtypes[mp->mt_type]) { + seen[mp->mt_type] = YES; + printf("\t%u mbufs allocated to %s\n", + mbstat.m_mtypes[mp->mt_type], mp->mt_name); + } + seen[MT_FREE] = YES; + for (i = 0; i < nmbtypes; i++) + if (!seen[i] && mbstat.m_mtypes[i]) { + printf("\t%u mbufs allocated to \n", + mbstat.m_mtypes[i], i); + } + printf("%u/%u mapped pages in use\n", + mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters); + totmem = totmbufs * MSIZE + mbstat.m_clusters * MCLBYTES; + totfree = mbstat.m_clfree * MCLBYTES; + printf("%u Kbytes allocated to network (%d%% in use)\n", + totmem / 1024, (totmem - totfree) * 100 / totmem); + printf("%u requests for memory denied\n", mbstat.m_drops); + printf("%u requests for memory delayed\n", mbstat.m_wait); + printf("%u calls to protocol drain routines\n", mbstat.m_drain); +} diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c new file mode 100644 index 0000000..7ca5e85 --- /dev/null +++ b/usr.bin/netstat/mroute.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 1989 Stephen Deering + * Copyright (c) 1992, 1993 + * The 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. + * + * @(#)mroute.c 8.1 (Berkeley) 6/6/93 + */ + +/* + * Print DVMRP multicast routing structures and statistics. + * + * MROUTING 1.0 + */ + +#include +#include +#include +#include + +#include +#include +#define KERNEL 1 +#include +#undef KERNEL + +#include +#include +#include "netstat.h" + +void +mroutepr(mrpaddr, mrtaddr, vifaddr) + u_long mrpaddr, mrtaddr, vifaddr; +{ + u_int mrtproto; + struct mrt *mrttable[MRTHASHSIZ]; + struct vif viftable[MAXVIFS]; + register struct mrt *mrt; + struct mrt smrt; + register struct vif *v; + register vifi_t vifi; + register struct in_addr *grp; + register int i, n; + register int banner_printed; + register int saved_nflag; + + if (mrpaddr == 0) { + printf("ip_mrtproto: symbol not in namelist\n"); + return; + } + + kread(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; + + kread(vifaddr, (char *)&viftable, sizeof(viftable)); + banner_printed = 0; + for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { + 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.s_addr)); + printf(" %-15.15s\n", (v->v_flags & VIFF_TUNNEL) ? + routename(v->v_rmt_addr.s_addr) : ""); + + n = v->v_lcl_grps_n; + grp = (struct in_addr *)malloc(n * sizeof(*grp)); + if (grp == NULL) { + printf("v_lcl_grps_n: malloc failed\n"); + return; + } + kread((u_long)v->v_lcl_grps, (caddr_t)grp, n * sizeof(*grp)); + for (i = 0; i < n; ++i) + printf("%51s %-15.15s\n", + "", routename((grp++)->s_addr)); + free(grp); + } + if (!banner_printed) + printf("\nVirtual Interface Table is empty\n"); + + kread(mrtaddr, (char *)&mrttable, sizeof(mrttable)); + banner_printed = 0; + for (i = 0; i < MRTHASHSIZ; ++i) { + for (mrt = mrttable[i]; mrt != NULL; mrt = mrt->mrt_next) { + if (!banner_printed) { + printf("\nMulticast Routing Table\n%s", + " Hash Origin-Subnet In-Vif Out-Vifs\n"); + banner_printed = 1; + } + + kread((u_long)mrt, (char *)&smrt, sizeof(*mrt)); + mrt = &smrt; + 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 (VIFM_ISSET(vifi, mrt->mrt_children)) + printf(" %u%c", + vifi, + VIFM_ISSET(vifi, mrt->mrt_leaves) ? + '*' : ' '); + printf("\n"); + } + } + if (!banner_printed) + printf("\nMulticast Routing Table is empty\n"); + + printf("\n"); + nflag = saved_nflag; +} + + +void +mrt_stats(mrpaddr, mstaddr) + u_long mrpaddr, mstaddr; +{ + u_int mrtproto; + struct mrtstat mrtstat; + + if(mrpaddr == 0) { + printf("ip_mrtproto: symbol not in namelist\n"); + return; + } + + kread(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; + } + + kread(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)); +} diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 new file mode 100644 index 0000000..fc0d303 --- /dev/null +++ b/usr.bin/netstat/netstat.1 @@ -0,0 +1,289 @@ +.\" Copyright (c) 1983, 1990, 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. +.\" +.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt NETSTAT 1 +.Os BSD 4.2 +.Sh NAME +.Nm netstat +.Nd show network status +.Sh SYNOPSIS +.Nm netstat +.Op Fl Aan +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Nm netstat +.Op Fl dghimnrs +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Nm netstat +.Op Fl dn +.Op Fl I Ar interface +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar wait +.Nm netstat +.Op Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Sh DESCRIPTION +The +.Nm netstat +command symbolically displays the contents of various network-related +data structures. +There are a number of output formats, +depending on the options for the information presented. +The first form of the command displays a list of active sockets for +each protocol. +The second form presents the contents of one of the other network +data structures according to the option selected. +Using the third form, with a +.Ar wait +interval specified, +.Nm netstat +will continuously display the information regarding packet +traffic on the configured network interfaces. +The fourth form displays statistics about the named protocol. +.Pp +The options have the following meaning: +.Bl -tag -width flag +.It Fl A +With the default display, +show the address of any protocol control blocks associated with sockets; used +for debugging. +.It Fl a +With the default display, +show the state of all sockets; normally sockets used by +server processes are not shown. +.It Fl d +With either interface display (option +.Fl i +or an interval, as described below), +show the number of dropped packets. +.It Fl f Ar address_family +Limit statistics or address control block reports to those +of the specified +.Ar address family . +The following address families +are recognized: +.Ar inet , +for +.Dv AF_INET , +.Ar ns , +for +.Dv AF_NS , +.Ar iso , +for +.Dv AF_ISO , +and +.Ar unix , +for +.Dv AF_UNIX . +.It Fl g +Show information related to multicast (group address) routing. +By default, show the IP Multicast virtual-interface and routing tables. +If the +.Fl s +option is also present, show multicast routing statistics. +.It Fl h +Show the state of the +.Tn IMP +host table (obsolete). +.It Fl I Ar interface +Show information about the specified interface; +used with a +.Ar wait +interval as described below. +.It Fl i +Show the state of interfaces which have been auto-configured +(interfaces statically configured into a system, but not +located at boot time are not shown). +If the +.Fl a +options is also present, multicast addresses currently in use are shown +for each Ethernet interface and for each IP interface address. +Multicast addresses are shown on separate lines following the interface +address with which they are associated. +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl m +Show statistics recorded by the memory management routines +(the network manages a private pool of memory buffers). +.It Fl N +Extract the name list from the specified system instead of the default +.Pa /vmunix . +.It Fl n +Show network addresses as numbers (normally +.Nm netstat +interprets addresses and attempts to display them +symbolically). +This option may be used with any of the display formats. +.It Fl p Ar protocol +Show statistics about +.Ar protocol , +which is either a well-known name for a protocol or an alias for it. Some +protocol names and aliases are listed in the file +.Pa /etc/protocols . +A null response typically means that there are no interesting numbers to +report. +The program will complain if +.Ar protocol +is unknown or if there is no statistics routine for it. +.It Fl s +Show per-protocol statistics. +If this option is repeated, counters with a value of zero are suppressed. +.It Fl r +Show the routing tables. +When +.Fl s +is also present, show routing statistics instead. +.It Fl w Ar wait +Show network interface statistics at intervals of +.Ar wait +seconds. +.El +.Pp +The default display, for active sockets, shows the local +and remote addresses, send and receive queue sizes (in bytes), protocol, +and the internal state of the protocol. +Address formats are of the form ``host.port'' or ``network.port'' +if a socket's address specifies a network but no specific host address. +When known the host and network addresses are displayed symbolically +according to the data bases +.Pa /etc/hosts +and +.Pa /etc/networks , +respectively. If a symbolic name for an address is unknown, or if +the +.Fl n +option is specified, the address is printed numerically, according +to the address family. +For more information regarding +the Internet ``dot format,'' +refer to +.Xr inet 3 ) . +Unspecified, +or ``wildcard'', addresses and ports appear as ``*''. +.Pp +The interface display provides a table of cumulative +statistics regarding packets transferred, errors, and collisions. +The network addresses of the interface +and the maximum transmission unit (``mtu'') are also displayed. +.Pp +The routing table display indicates the available routes and +their status. Each route consists of a destination host or network +and a gateway to use in forwarding packets. The flags field shows +a collection of information about the route stored as +binary choices. The individual flags are discussed in more +detail in the +.Xr route 8 +and +.Xr route 4 +manual pages. +The mapping between letters and flags is: +.Bl -column XXXX RTF_BLACKHOLE +1 RTF_PROTO2 Protocol specific routing flag #1 +2 RTF_PROTO1 Protocol specific routing flag #2 +B RTF_BLACKHOLE Just discard pkts (during updates) +C RTF_CLONING Generate new routes on use +D RTF_DYNAMIC Created dynamically (by redirect) +G RTF_GATEWAY Destination requires forwarding by intermediary +H RTF_HOST Host entry (net otherwise) +L RTF_LLINFO Valid protocol to link address translation. +M RTF_MODIFIED Modified dynamically (by redirect) +R RTF_REJECT Host or net unreachable +S RTF_STATIC Manually added +U RTF_UP Route usable +X RTF_XRESOLVE External daemon translates proto to link address +.El +.Pp +Direct routes are created for each +interface attached to the local host; +the gateway field for such entries shows the address of the outgoing interface. +The refcnt field gives the +current number of active uses of the route. Connection oriented +protocols normally hold on to a single route for the duration of +a connection while connectionless protocols obtain a route while sending +to the same destination. +The use field provides a count of the number of packets +sent using that route. The interface entry indicates the network +interface utilized for the route. +.Pp +When +.Nm netstat +is invoked with the +.Fl w +option and a +.Ar wait +interval argument, it displays a running count of statistics related to +network interfaces. +An obsolescent version of this option used a numeric parameter +with no option, and is currently supported for backward compatibility. +This display consists of a column for the primary interface (the first +interface found during autoconfiguration) and a column summarizing +information for all interfaces. +The primary interface may be replaced with another interface with the +.Fl I +option. +The first line of each screen of information contains a summary since the +system was last rebooted. Subsequent lines of output show values +accumulated over the preceding interval. +.Sh SEE ALSO +.Xr iostat 1 , +.Xr nfsstat 1 , +.Xr ps 1 , +.Xr vmstat 1 , +.Xr hosts 5 , +.Xr networks 5 , +.Xr protocols 5 , +.Xr services 5 , +.Xr trpt 8 , +.Xr trsp 8 +.Sh HISTORY +The +.Nm netstat +command appeared in +.Bx 4.2 . +.\" .Sh FILES +.\" .Bl -tag -width /dev/kmem -compact +.\" .It Pa /vmunix +.\" default kernel namelist +.\" .It Pa /dev/kmem +.\" default memory file +.\" .El +.Sh BUGS +The notion of errors is ill-defined. diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h new file mode 100644 index 0000000..8f2aa1f --- /dev/null +++ b/usr.bin/netstat/netstat.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1992, 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)netstat.h 8.2 (Berkeley) 1/4/94 + */ + +#include + +int Aflag; /* show addresses of protocol control block */ +int aflag; /* show all sockets (including servers) */ +int dflag; /* show i/f dropped packets */ +int gflag; /* show group (multicast) routing or stats */ +int iflag; /* show interfaces */ +int mflag; /* show memory stats */ +int nflag; /* show addresses numerically */ +int pflag; /* show given protocol */ +int rflag; /* show routing tables (or routing stats) */ +int sflag; /* show protocol statistics */ +int tflag; /* show i/f watchdog timers */ + +int interval; /* repeat interval for i/f stats */ + +char *interface; /* desired i/f for stats, or NULL for all i/fs */ +int unit; /* unit number for above */ + +int af; /* address family */ + +char *prog; /* program name */ + + +int kread __P((u_long addr, char *buf, int size)); +char *plural __P((int)); +char *plurales __P((int)); + +void protopr __P((u_long, char *)); +void tcp_stats __P((u_long, char *)); +void udp_stats __P((u_long, char *)); +void ip_stats __P((u_long, char *)); +void icmp_stats __P((u_long, char *)); +void igmp_stats __P((u_long, char *)); +void protopr __P((u_long, char *)); + +void mbpr(u_long); + +void hostpr __P((u_long, u_long)); +void impstats __P((u_long, u_long)); + +void intpr __P((int, u_long)); + +void pr_rthdr __P(()); +void pr_family __P((int)); +void rt_stats __P((u_long)); +char *ns_phost __P((struct sockaddr *)); +void upHex __P((char *)); + +char *routename __P((u_long)); +char *netname __P((u_long, u_long)); +char *ns_print __P((struct sockaddr *)); +void routepr __P((u_long)); + +void nsprotopr __P((u_long, char *)); +void spp_stats __P((u_long, char *)); +void idp_stats __P((u_long, char *)); +void nserr_stats __P((u_long, char *)); + +void intpr __P((int, u_long)); + +void unixpr __P((u_long)); + +void esis_stats __P((u_long, char *)); +void clnp_stats __P((u_long, char *)); +void cltp_stats __P((u_long, char *)); +void iso_protopr __P((u_long, char *)); +void iso_protopr1 __P((u_long, int)); +void tp_protopr __P((u_long, char *)); +void tp_inproto __P((u_long)); +void tp_stats __P((caddr_t, caddr_t)); + +void mroutepr __P((u_long, u_long, u_long)); +void mrt_stats __P((u_long, u_long)); diff --git a/usr.bin/netstat/ns.c b/usr.bin/netstat/ns.c new file mode 100644 index 0000000..a7bee2f --- /dev/null +++ b/usr.bin/netstat/ns.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)ns.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SANAMES +#include + +#include +#include +#include +#include +#include "netstat.h" + +struct nspcb nspcb; +struct sppcb sppcb; +struct socket sockb; + +static char *ns_prpr __P((struct ns_addr *)); +static void ns_erputil __P((int, int)); + +static int first = 1; + +/* + * Print a summary of connections related to a Network Systems + * protocol. For SPP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ + +void +nsprotopr(off, name) + u_long off; + char *name; +{ + struct nspcb cb; + register struct nspcb *prev, *next; + int isspp; + + if (off == 0) + return; + isspp = strcmp(name, "spp") == 0; + kread(off, (char *)&cb, sizeof (struct nspcb)); + nspcb = cb; + prev = (struct nspcb *)off; + if (nspcb.nsp_next == (struct nspcb *)off) + return; + for (;nspcb.nsp_next != (struct nspcb *)off; prev = next) { + u_long ppcb; + + next = nspcb.nsp_next; + kread((u_long)next, (char *)&nspcb, sizeof (nspcb)); + if (nspcb.nsp_prev != prev) { + printf("???\n"); + break; + } + if (!aflag && ns_nullhost(nspcb.nsp_faddr) ) { + continue; + } + kread((u_long)nspcb.nsp_socket, + (char *)&sockb, sizeof (sockb)); + ppcb = (u_long) nspcb.nsp_pcb; + if (ppcb) { + if (isspp) { + kread(ppcb, (char *)&sppcb, sizeof (sppcb)); + } else continue; + } else + if (isspp) continue; + if (first) { + printf("Active NS connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + if (Aflag) + printf("%8x ", ppcb); + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + printf(" %-22.22s", ns_prpr(&nspcb.nsp_laddr)); + printf(" %-22.22s", ns_prpr(&nspcb.nsp_faddr)); + if (isspp) { + extern char *tcpstates[]; + if (sppcb.s_state >= TCP_NSTATES) + printf(" %d", sppcb.s_state); + else + printf(" %s", tcpstates[sppcb.s_state]); + } + putchar('\n'); + prev = next; + } +} +#define ANY(x,y,z) \ + ((x) ? printf("\t%d %s%s%s -- %s\n",x,y,plural(x),z,"x") : 0) + +/* + * Dump SPP statistics structure. + */ +void +spp_stats(off, name) + u_long off; + char *name; +{ + struct spp_istat spp_istat; +#define sppstat spp_istat.newstats + + if (off == 0) + return; + kread(off, (char *)&spp_istat, sizeof (spp_istat)); + printf("%s:\n", name); + ANY(spp_istat.nonucn, "connection", " dropped due to no new sockets "); + ANY(spp_istat.gonawy, "connection", " terminated due to our end dying"); + ANY(spp_istat.nonucn, "connection", + " dropped due to inability to connect"); + ANY(spp_istat.noconn, "connection", + " dropped due to inability to connect"); + ANY(spp_istat.notme, "connection", + " incompleted due to mismatched id's"); + ANY(spp_istat.wrncon, "connection", " dropped due to mismatched id's"); + ANY(spp_istat.bdreas, "packet", " dropped out of sequence"); + ANY(spp_istat.lstdup, "packet", " duplicating the highest packet"); + ANY(spp_istat.notyet, "packet", " refused as exceeding allocation"); + ANY(sppstat.spps_connattempt, "connection", " initiated"); + ANY(sppstat.spps_accepts, "connection", " accepted"); + ANY(sppstat.spps_connects, "connection", " established"); + ANY(sppstat.spps_drops, "connection", " dropped"); + ANY(sppstat.spps_conndrops, "embryonic connection", " dropped"); + ANY(sppstat.spps_closed, "connection", " closed (includes drops)"); + ANY(sppstat.spps_segstimed, "packet", " where we tried to get rtt"); + ANY(sppstat.spps_rttupdated, "time", " we got rtt"); + ANY(sppstat.spps_delack, "delayed ack", " sent"); + ANY(sppstat.spps_timeoutdrop, "connection", " dropped in rxmt timeout"); + ANY(sppstat.spps_rexmttimeo, "retransmit timeout", ""); + ANY(sppstat.spps_persisttimeo, "persist timeout", ""); + ANY(sppstat.spps_keeptimeo, "keepalive timeout", ""); + ANY(sppstat.spps_keepprobe, "keepalive probe", " sent"); + ANY(sppstat.spps_keepdrops, "connection", " dropped in keepalive"); + ANY(sppstat.spps_sndtotal, "total packet", " sent"); + ANY(sppstat.spps_sndpack, "data packet", " sent"); + ANY(sppstat.spps_sndbyte, "data byte", " sent"); + ANY(sppstat.spps_sndrexmitpack, "data packet", " retransmitted"); + ANY(sppstat.spps_sndrexmitbyte, "data byte", " retransmitted"); + ANY(sppstat.spps_sndacks, "ack-only packet", " sent"); + ANY(sppstat.spps_sndprobe, "window probe", " sent"); + ANY(sppstat.spps_sndurg, "packet", " sent with URG only"); + ANY(sppstat.spps_sndwinup, "window update-only packet", " sent"); + ANY(sppstat.spps_sndctrl, "control (SYN|FIN|RST) packet", " sent"); + ANY(sppstat.spps_sndvoid, "request", " to send a non-existant packet"); + ANY(sppstat.spps_rcvtotal, "total packet", " received"); + ANY(sppstat.spps_rcvpack, "packet", " received in sequence"); + ANY(sppstat.spps_rcvbyte, "byte", " received in sequence"); + ANY(sppstat.spps_rcvbadsum, "packet", " received with ccksum errs"); + ANY(sppstat.spps_rcvbadoff, "packet", " received with bad offset"); + ANY(sppstat.spps_rcvshort, "packet", " received too short"); + ANY(sppstat.spps_rcvduppack, "duplicate-only packet", " received"); + ANY(sppstat.spps_rcvdupbyte, "duplicate-only byte", " received"); + ANY(sppstat.spps_rcvpartduppack, "packet", " with some duplicate data"); + ANY(sppstat.spps_rcvpartdupbyte, "dup. byte", " in part-dup. packet"); + ANY(sppstat.spps_rcvoopack, "out-of-order packet", " received"); + ANY(sppstat.spps_rcvoobyte, "out-of-order byte", " received"); + ANY(sppstat.spps_rcvpackafterwin, "packet", " with data after window"); + ANY(sppstat.spps_rcvbyteafterwin, "byte", " rcvd after window"); + ANY(sppstat.spps_rcvafterclose, "packet", " rcvd after 'close'"); + ANY(sppstat.spps_rcvwinprobe, "rcvd window probe packet", ""); + ANY(sppstat.spps_rcvdupack, "rcvd duplicate ack", ""); + ANY(sppstat.spps_rcvacktoomuch, "rcvd ack", " for unsent data"); + ANY(sppstat.spps_rcvackpack, "rcvd ack packet", ""); + ANY(sppstat.spps_rcvackbyte, "byte", " acked by rcvd acks"); + ANY(sppstat.spps_rcvwinupd, "rcvd window update packet", ""); +} +#undef ANY +#define ANY(x,y,z) ((x) ? printf("\t%d %s%s%s\n",x,y,plural(x),z) : 0) + +/* + * Dump IDP statistics structure. + */ +void +idp_stats(off, name) + u_long off; + char *name; +{ + struct idpstat idpstat; + + if (off == 0) + return; + kread(off, (char *)&idpstat, sizeof (idpstat)); + printf("%s:\n", name); + ANY(idpstat.idps_toosmall, "packet", " smaller than a header"); + ANY(idpstat.idps_tooshort, "packet", " smaller than advertised"); + ANY(idpstat.idps_badsum, "packet", " with bad checksums"); +} + +static struct { + u_short code; + char *name; + char *where; +} ns_errnames[] = { + {0, "Unspecified Error", " at Destination"}, + {1, "Bad Checksum", " at Destination"}, + {2, "No Listener", " at Socket"}, + {3, "Packet", " Refused due to lack of space at Destination"}, + {01000, "Unspecified Error", " while gatewayed"}, + {01001, "Bad Checksum", " while gatewayed"}, + {01002, "Packet", " forwarded too many times"}, + {01003, "Packet", " too large to be forwarded"}, + {-1, 0, 0}, +}; + +/* + * Dump NS Error statistics structure. + */ +/*ARGSUSED*/ +void +nserr_stats(off, name) + u_long off; + char *name; +{ + struct ns_errstat ns_errstat; + register int j; + register int histoprint = 1; + int z; + + if (off == 0) + return; + kread(off, (char *)&ns_errstat, sizeof (ns_errstat)); + printf("NS error statistics:\n"); + ANY(ns_errstat.ns_es_error, "call", " to ns_error"); + ANY(ns_errstat.ns_es_oldshort, "error", + " ignored due to insufficient addressing"); + ANY(ns_errstat.ns_es_oldns_err, "error request", + " in response to error packets"); + ANY(ns_errstat.ns_es_tooshort, "error packet", + " received incomplete"); + ANY(ns_errstat.ns_es_badcode, "error packet", + " received of unknown type"); + for(j = 0; j < NS_ERR_MAX; j ++) { + z = ns_errstat.ns_es_outhist[j]; + if (z && histoprint) { + printf("Output Error Histogram:\n"); + histoprint = 0; + } + ns_erputil(z, ns_errstat.ns_es_codes[j]); + + } + histoprint = 1; + for(j = 0; j < NS_ERR_MAX; j ++) { + z = ns_errstat.ns_es_inhist[j]; + if (z && histoprint) { + printf("Input Error Histogram:\n"); + histoprint = 0; + } + ns_erputil(z, ns_errstat.ns_es_codes[j]); + } +} + +static void +ns_erputil(z, c) + int z, c; +{ + int j; + char codebuf[30]; + char *name, *where; + + for(j = 0;; j ++) { + if ((name = ns_errnames[j].name) == 0) + break; + if (ns_errnames[j].code == c) + break; + } + if (name == 0) { + if (c > 01000) + where = "in transit"; + else + where = "at destination"; + sprintf(codebuf, "Unknown XNS error code 0%o", c); + name = codebuf; + } else + where = ns_errnames[j].where; + ANY(z, name, where); +} + +static struct sockaddr_ns ssns = {AF_NS}; + +static +char *ns_prpr(x) + struct ns_addr *x; +{ + struct sockaddr_ns *sns = &ssns; + + sns->sns_addr = *x; + return(ns_print((struct sockaddr *)sns)); +} diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c new file mode 100644 index 0000000..7f4ebb6 --- /dev/null +++ b/usr.bin/netstat/route.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 1983, 1988, 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[] = "@(#)route.c 8.3 (Berkeley) 3/9/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#define KERNEL +#include +#undef KERNEL +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include "netstat.h" + +#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) + +/* + * Definitions for showing gateway flags. + */ +struct bits { + short b_mask; + char b_val; +} bits[] = { + { RTF_UP, 'U' }, + { RTF_GATEWAY, 'G' }, + { RTF_HOST, 'H' }, + { RTF_REJECT, 'R' }, + { RTF_DYNAMIC, 'D' }, + { RTF_MODIFIED, 'M' }, + { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ + { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */ + { RTF_CLONING, 'C' }, + { RTF_XRESOLVE, 'X' }, + { RTF_LLINFO, 'L' }, + { RTF_STATIC, 'S' }, + { RTF_PROTO1, '1' }, + { RTF_PROTO2, '2' }, + { 0 } +}; + +static union { + struct sockaddr u_sa; + u_short u_data[128]; +} pt_u; + +int do_rtent = 0; +struct rtentry rtentry; +struct radix_node rnode; +struct radix_mask rmask; + +int NewTree = 0; + +static struct sockaddr *kgetsa __P((struct sockaddr *)); +static void p_tree __P((struct radix_node *)); +static void p_rtnode __P(()); +static void ntreestuff __P(()); +static void np_rtentry __P((struct rt_msghdr *)); +static void p_sockaddr __P((struct sockaddr *, int, int)); +static void p_flags __P((int, char *)); +static void p_rtentry __P((struct rtentry *)); + +/* + * Print routing tables. + */ +void +routepr(rtree) + u_long rtree; +{ + struct radix_node_head *rnh, head; + int i; + + printf("Routing tables\n"); + + if (Aflag == 0 && NewTree) + ntreestuff(); + else { + if (rtree == 0) { + printf("rt_tables: symbol not in namelist\n"); + return; + } + + kget(rtree, rt_tables); + for (i = 0; i <= AF_MAX; i++) { + if ((rnh = rt_tables[i]) == 0) + continue; + kget(rnh, head); + if (i == AF_UNSPEC) { + if (Aflag && af == 0) { + printf("Netmasks:\n"); + p_tree(head.rnh_treetop); + } + } else if (af == AF_UNSPEC || af == i) { + pr_family(i); + do_rtent = 1; + pr_rthdr(); + p_tree(head.rnh_treetop); + } + } + } +} + +/* + * Print address family header before a section of the routing table. + */ +void +pr_family(af) + int af; +{ + char *afname; + + switch (af) { + case AF_INET: + afname = "Internet"; + break; + case AF_NS: + afname = "XNS"; + break; + case AF_ISO: + afname = "ISO"; + break; + case AF_CCITT: + afname = "X.25"; + break; + default: + afname = NULL; + break; + } + if (afname) + printf("\n%s:\n", afname); + else + printf("\nProtocol Family %d:\n", af); +} + +/* column widths; each followed by one space */ +#define WID_DST 16 /* width of destination column */ +#define WID_GW 18 /* width of gateway column */ + +/* + * Print header for routing table columns. + */ +void +pr_rthdr() +{ + + if (Aflag) + printf("%-8.8s ","Address"); + printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %s\n", + WID_DST, WID_DST, "Destination", + WID_GW, WID_GW, "Gateway", + "Flags", "Refs", "Use", "Interface"); +} + +static struct sockaddr * +kgetsa(dst) + register struct sockaddr *dst; +{ + + kget(dst, pt_u.u_sa); + if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) + kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); + return (&pt_u.u_sa); +} + +static void +p_tree(rn) + struct radix_node *rn; +{ + +again: + kget(rn, rnode); + if (rnode.rn_b < 0) { + if (Aflag) + printf("%-8.8x ", rn); + if (rnode.rn_flags & RNF_ROOT) { + if (Aflag) + printf("(root node)%s", + rnode.rn_dupedkey ? " =>\n" : "\n"); + } else if (do_rtent) { + kget(rn, rtentry); + p_rtentry(&rtentry); + if (Aflag) + p_rtnode(); + } else { + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), + 0, 44); + putchar('\n'); + } + if (rn = rnode.rn_dupedkey) + goto again; + } else { + if (Aflag && do_rtent) { + printf("%-8.8x ", rn); + p_rtnode(); + } + rn = rnode.rn_r; + p_tree(rnode.rn_l); + p_tree(rn); + } +} + +char nbuf[20]; + +static void +p_rtnode() +{ + struct radix_mask *rm = rnode.rn_mklist; + + if (rnode.rn_b < 0) { + if (rnode.rn_mask) { + printf("\t mask "); + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), + 0, -1); + } else if (rm == 0) + return; + } else { + sprintf(nbuf, "(%d)", rnode.rn_b); + printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r); + } + while (rm) { + kget(rm, rmask); + sprintf(nbuf, " %d refs, ", rmask.rm_refs); + printf(" mk = %8.8x {(%d),%s", + rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); + p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1); + putchar('}'); + if (rm = rmask.rm_mklist) + printf(" ->"); + } + putchar('\n'); +} + +static void +ntreestuff() +{ + size_t needed; + int mib[6]; + char *buf, *next, *lim; + register struct rt_msghdr *rtm; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + { perror("route-sysctl-estimate"); exit(1);} + if ((buf = malloc(needed)) == 0) + { printf("out of space\n"); exit(1);} + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + { perror("sysctl of routing table"); exit(1);} + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + np_rtentry(rtm); + } +} + +static void +np_rtentry(rtm) + register struct rt_msghdr *rtm; +{ + register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); +#ifdef notdef + static int masks_done, banner_printed; +#endif + static int old_af; + int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; + +#ifdef notdef + /* for the moment, netmasks are skipped over */ + if (!banner_printed) { + printf("Netmasks:\n"); + banner_printed = 1; + } + if (masks_done == 0) { + if (rtm->rtm_addrs != RTA_DST ) { + masks_done = 1; + af = sa->sa_family; + } + } else +#endif + af = sa->sa_family; + if (af != old_af) { + pr_family(af); + old_af = af; + } + if (rtm->rtm_addrs == RTA_DST) + p_sockaddr(sa, 0, 36); + else { + p_sockaddr(sa, rtm->rtm_flags, 16); + if (sa->sa_len == 0) + sa->sa_len = sizeof(long); + sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + p_sockaddr(sa, 0, 18); + } + p_flags(rtm->rtm_flags & interesting, "%-6.6s "); + putchar('\n'); +} + +static void +p_sockaddr(sa, flags, width) + struct sockaddr *sa; + int flags, width; +{ + char workbuf[128], *cplim; + register char *cp = workbuf; + + switch(sa->sa_family) { + case AF_INET: + { + register struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + cp = (sin->sin_addr.s_addr == 0) ? "default" : + ((flags & RTF_HOST) ? + routename(sin->sin_addr.s_addr) : + netname(sin->sin_addr.s_addr, 0L)); + break; + } + + case AF_NS: + cp = ns_print(sa); + break; + + case AF_LINK: + { + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; + + if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && + sdl->sdl_slen == 0) + (void) sprintf(workbuf, "link#%d", sdl->sdl_index); + else switch (sdl->sdl_type) { + case IFT_ETHER: + { + register int i; + register u_char *lla = (u_char *)sdl->sdl_data + + sdl->sdl_nlen; + + cplim = ""; + for (i = 0; i < sdl->sdl_alen; i++, lla++) { + cp += sprintf(cp, "%s%x", cplim, *lla); + cplim = ":"; + } + cp = workbuf; + break; + } + default: + cp = link_ntoa(sdl); + break; + } + break; + } + + default: + { + register u_char *s = (u_char *)sa->sa_data, *slim; + + slim = sa->sa_len + (u_char *) sa; + cplim = cp + sizeof(workbuf) - 6; + cp += sprintf(cp, "(%d)", sa->sa_family); + while (s < slim && cp < cplim) { + cp += sprintf(cp, " %02x", *s++); + if (s < slim) + cp += sprintf(cp, "%02x", *s++); + } + cp = workbuf; + } + } + if (width < 0 ) + printf("%s ", cp); + else { + if (nflag) + printf("%-*s ", width, cp); + else + printf("%-*.*s ", width, width, cp); + } +} + +static void +p_flags(f, format) + register int f; + char *format; +{ + char name[33], *flags; + register struct bits *p = bits; + + for (flags = name; p->b_mask; p++) + if (p->b_mask & f) + *flags++ = p->b_val; + *flags = '\0'; + printf(format, name); +} + +static void +p_rtentry(rt) + register struct rtentry *rt; +{ + static struct ifnet ifnet, *lastif; + static char name[16]; + + p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST); + p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW); + p_flags(rt->rt_flags, "%-6.6s "); + printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); + if (rt->rt_ifp) { + if (rt->rt_ifp != lastif) { + kget(rt->rt_ifp, ifnet); + kread((u_long)ifnet.if_name, name, 16); + lastif = rt->rt_ifp; + } + printf(" %.15s%d%s", name, ifnet.if_unit, + rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); + } + putchar('\n'); +} + +char * +routename(in) + u_long in; +{ + register char *cp; + static char line[MAXHOSTNAMELEN + 1]; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + + if (first) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!nflag) { + hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), + AF_INET); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + if (cp) + strncpy(line, cp, sizeof(line) - 1); + else { +#define C(x) ((x) & 0xff) + in = ntohl(in); + sprintf(line, "%u.%u.%u.%u", + C(in >> 24), C(in >> 16), C(in >> 8), C(in)); + } + return (line); +} + +/* + * Return the name of the network whose address is given. + * The address is assumed to be that of a net or subnet, not a host. + */ +char * +netname(in, mask) + u_long in, mask; +{ + char *cp = 0; + static char line[MAXHOSTNAMELEN + 1]; + struct netent *np = 0; + u_long net; + register int i; + int subnetshift; + + i = ntohl(in); + if (!nflag && i) { + if (mask == 0) { + if (IN_CLASSA(i)) { + mask = IN_CLASSA_NET; + subnetshift = 8; + } else if (IN_CLASSB(i)) { + mask = IN_CLASSB_NET; + subnetshift = 8; + } else { + mask = IN_CLASSC_NET; + subnetshift = 4; + } + /* + * If there are more bits than the standard mask + * would suggest, subnets must be in use. + * Guess at the subnet mask, assuming reasonable + * width subnet fields. + */ + while (i &~ mask) + mask = (long)mask >> subnetshift; + } + net = i & mask; + while ((mask & 1) == 0) + mask >>= 1, net >>= 1; + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp) + strncpy(line, cp, sizeof(line) - 1); + else if ((i & 0xffffff) == 0) + sprintf(line, "%u", C(i >> 24)); + else if ((i & 0xffff) == 0) + sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); + else if ((i & 0xff) == 0) + sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); + else + sprintf(line, "%u.%u.%u.%u", C(i >> 24), + C(i >> 16), C(i >> 8), C(i)); + return (line); +} + +/* + * Print routing statistics + */ +void +rt_stats(off) + u_long off; +{ + struct rtstat rtstat; + + if (off == 0) { + printf("rtstat: symbol not in namelist\n"); + return; + } + kread(off, (char *)&rtstat, sizeof (rtstat)); + printf("routing:\n"); + printf("\t%u bad routing redirect%s\n", + rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); + printf("\t%u dynamically created route%s\n", + rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); + printf("\t%u new gateway%s due to redirects\n", + rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); + printf("\t%u destination%s found unreachable\n", + rtstat.rts_unreach, plural(rtstat.rts_unreach)); + printf("\t%u use%s of a wildcard route\n", + rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); +} +short ns_nullh[] = {0,0,0}; +short ns_bh[] = {-1,-1,-1}; + +char * +ns_print(sa) + register struct sockaddr *sa; +{ + register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; + struct ns_addr work; + union { union ns_net net_e; u_long long_e; } net; + u_short port; + static char mybuf[50], cport[10], chost[25]; + char *host = ""; + register char *p; register u_char *q; + + work = sns->sns_addr; + port = ntohs(work.x_port); + work.x_port = 0; + net.net_e = work.x_net; + if (ns_nullhost(work) && net.long_e == 0) { + if (port ) { + sprintf(mybuf, "*.%xH", port); + upHex(mybuf); + } else + sprintf(mybuf, "*.*"); + return (mybuf); + } + + if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { + host = "any"; + } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { + host = "*"; + } else { + q = work.x_host.c_host; + sprintf(chost, "%02x%02x%02x%02x%02x%02xH", + q[0], q[1], q[2], q[3], q[4], q[5]); + for (p = chost; *p == '0' && p < chost + 12; p++) + continue; + host = p; + } + if (port) + sprintf(cport, ".%xH", htons(port)); + else + *cport = 0; + + sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); + upHex(mybuf); + return(mybuf); +} + +char * +ns_phost(sa) + struct sockaddr *sa; +{ + register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; + struct sockaddr_ns work; + static union ns_net ns_zeronet; + char *p; + + work = *sns; + work.sns_addr.x_port = 0; + work.sns_addr.x_net = ns_zeronet; + + p = ns_print((struct sockaddr *)&work); + if (strncmp("0H.", p, 3) == 0) p += 3; + return(p); +} + +void +upHex(p0) + char *p0; +{ + register char *p = p0; + for (; *p; p++) switch (*p) { + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + *p += ('A' - 'a'); + } +} diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c new file mode 100644 index 0000000..0310b68 --- /dev/null +++ b/usr.bin/netstat/unix.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 1983, 1988, 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[] = "@(#)unix.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Display protocol blocks in the unix domain. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define KERNEL +struct uio; +struct proc; +#include + +#include + +#include +#include +#include "netstat.h" + +static void unixdomainpr __P((struct socket *, caddr_t)); + +static struct file *file, *fileNFILE; +static int nfiles; +extern kvm_t *kvmd; + +void +unixpr(off) + u_long off; +{ + register struct file *fp; + struct socket sock, *so = &sock; + char *filebuf; + struct protosw *unixsw = (struct protosw *)off; + + filebuf = (char *)kvm_getfiles(kvmd, KERN_FILE, 0, &nfiles); + if (filebuf == 0) { + printf("Out of memory (file table).\n"); + return; + } + file = (struct file *)(filebuf + sizeof(fp)); + fileNFILE = file + nfiles; + for (fp = file; fp < fileNFILE; fp++) { + if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET) + continue; + if (kread((u_long)fp->f_data, (char *)so, sizeof (*so))) + continue; + /* kludge */ + if (so->so_proto >= unixsw && so->so_proto <= unixsw + 2) + if (so->so_pcb) + unixdomainpr(so, fp->f_data); + } +} + +static char *socktype[] = + { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; + +static void +unixdomainpr(so, soaddr) + register struct socket *so; + caddr_t soaddr; +{ + struct unpcb unpcb, *unp = &unpcb; + struct mbuf mbuf, *m; + struct sockaddr_un *sa; + static int first = 1; + + if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp))) + return; + if (unp->unp_addr) { + m = &mbuf; + if (kread((u_long)unp->unp_addr, (char *)m, sizeof (*m))) + m = (struct mbuf *)0; + sa = (struct sockaddr_un *)(m->m_dat); + } else + m = (struct mbuf *)0; + if (first) { + printf("Active UNIX domain sockets\n"); + printf( +"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n", + "Address", "Type", "Recv-Q", "Send-Q", + "Inode", "Conn", "Refs", "Nextref"); + first = 0; + } + printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x", + soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc, + unp->unp_vnode, unp->unp_conn, + unp->unp_refs, unp->unp_nextref); + if (m) + printf(" %.*s", + m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)), + sa->sun_path); + putchar('\n'); +} diff --git a/usr.bin/nfsstat/Makefile b/usr.bin/nfsstat/Makefile new file mode 100644 index 0000000..6d79ce7 --- /dev/null +++ b/usr.bin/nfsstat/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= nfsstat +CFLAGS+=-DNFS +DPADD= ${LIBKVM} +LDADD= -lkvm +BINGRP= kmem +BINMODE=2555 + +.include diff --git a/usr.bin/nfsstat/nfsstat.1 b/usr.bin/nfsstat/nfsstat.1 new file mode 100644 index 0000000..3acda6c --- /dev/null +++ b/usr.bin/nfsstat/nfsstat.1 @@ -0,0 +1,88 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)nfsstat.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt NFSSTAT 1 +.Os BSD 4.4 +.Sh NAME +.Nm nfsstat +.Nd display +.Tn NFS +statistics +.Sh SYNOPSIS +.Nm nfsstat +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar wait +.Sh DESCRIPTION +.Nm Nfsstat +displays statistics kept about +.Tn NFS +client and server activity. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl N +Extract the name list from the specified system instead of the default +.Pa /vmunix . +.It Fl w +Display a shorter summary of +.Tn NFS +activity for both the client and server at +.Ar wait +second intervals. +.El +.Sh FILES +.Bl -tag -width /dev/kmem -compact +.It Pa /vmunix +default kernel namelist +.It Pa /dev/kmem +default memory file +.El +.Sh SEE ALSO +.Xr fstat 1 , +.Xr netstat 1 , +.Xr ps 1 , +.Xr systat 1 , +.Xr vmstat 1 , +.Xr iostat 8 , +.Xr pstat 8 , +.Sh HISTORY +The +.Nm nfsstat +command appears in +.Bx 4.4 . diff --git a/usr.bin/nfsstat/nfsstat.c b/usr.bin/nfsstat/nfsstat.c new file mode 100644 index 0000000..c57e658 --- /dev/null +++ b/usr.bin/nfsstat/nfsstat.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1983, 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)nfsstat.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#if BSD >= 199103 +#define NEWVM +#endif +#ifndef NEWVM +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nlist nl[] = { +#define N_NFSSTAT 0 + { "_nfsstats" }, + "", +}; +kvm_t *kd; + +void intpr(), printhdr(), sidewaysintpr(), usage(); + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + extern char *optarg; + u_int interval; + int ch; + char *memf, *nlistf; + char errbuf[80]; + + interval = 0; + memf = nlistf = NULL; + while ((ch = getopt(argc, argv, "M:N:w:")) != EOF) + switch(ch) { + case 'M': + memf = optarg; + break; + case 'N': + nlistf = optarg; + break; + case 'w': + interval = atoi(optarg); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + interval = atoi(*argv); + if (*++argv) { + nlistf = *argv; + if (*++argv) + memf = *argv; + } + } +#endif + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == 0) { + fprintf(stderr, "nfsstat: kvm_openfiles: %s\n", errbuf); + exit(1); + } + if (kvm_nlist(kd, nl) != 0) { + fprintf(stderr, "nfsstat: kvm_nlist: can't get names\n"); + exit(1); + } + + if (interval) + sidewaysintpr(interval, nl[N_NFSSTAT].n_value); + else + intpr(nl[N_NFSSTAT].n_value); + exit(0); +} + +/* + * Print a description of the nfs stats. + */ +void +intpr(nfsstataddr) + u_long nfsstataddr; +{ + struct nfsstats nfsstats; + + if (kvm_read(kd, (u_long)nfsstataddr, (char *)&nfsstats, sizeof(struct nfsstats)) < 0) { + fprintf(stderr, "nfsstat: kvm_read failed\n"); + exit(1); + } + printf("Client Info:\n"); + printf("Rpc Counts:\n"); + printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", + "Getattr", "Setattr", "Lookup", "Readlink", "Read", + "Write", "Create", "Remove"); + printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", + nfsstats.rpccnt[NFSPROC_GETATTR], + nfsstats.rpccnt[NFSPROC_SETATTR], + nfsstats.rpccnt[NFSPROC_LOOKUP], + nfsstats.rpccnt[NFSPROC_READLINK], + nfsstats.rpccnt[NFSPROC_READ], + nfsstats.rpccnt[NFSPROC_WRITE], + nfsstats.rpccnt[NFSPROC_CREATE], + nfsstats.rpccnt[NFSPROC_REMOVE]); + printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", + "Rename", "Link", "Symlink", "Mkdir", "Rmdir", + "Readdir", "Statfs", "RdirLook"); + printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", + nfsstats.rpccnt[NFSPROC_RENAME], + nfsstats.rpccnt[NFSPROC_LINK], + nfsstats.rpccnt[NFSPROC_SYMLINK], + nfsstats.rpccnt[NFSPROC_MKDIR], + nfsstats.rpccnt[NFSPROC_RMDIR], + nfsstats.rpccnt[NFSPROC_READDIR], + nfsstats.rpccnt[NFSPROC_STATFS], + nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]); + printf("%9.9s %9.9s %9.9s\n", + "GLease", "Vacate", "Evict"); + printf("%9d %9d %9d\n", + nfsstats.rpccnt[NQNFSPROC_GETLEASE], + nfsstats.rpccnt[NQNFSPROC_VACATED], + nfsstats.rpccnt[NQNFSPROC_EVICTED]); + printf("Rpc Info:\n"); + printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", + "TimedOut", "Invalid", "X Replies", "Retries", "Requests"); + printf("%9d %9d %9d %9d %9d\n", + nfsstats.rpctimeouts, + nfsstats.rpcinvalid, + nfsstats.rpcunexpected, + nfsstats.rpcretries, + nfsstats.rpcrequests); + printf("Cache Info:\n"); + printf("%9.9s %9.9s %9.9s %9.9s", + "Attr Hits", "Misses", "Lkup Hits", "Misses"); + printf(" %9.9s %9.9s %9.9s %9.9s\n", + "BioR Hits", "Misses", "BioW Hits", "Misses"); + printf("%9d %9d %9d %9d", + nfsstats.attrcache_hits, nfsstats.attrcache_misses, + nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); + printf(" %9d %9d %9d %9d\n", + nfsstats.biocache_reads-nfsstats.read_bios, + nfsstats.read_bios, + nfsstats.biocache_writes-nfsstats.write_bios, + nfsstats.write_bios); + printf("%9.9s %9.9s %9.9s %9.9s", + "BioRLHits", "Misses", "BioD Hits", "Misses"); + printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); + printf("%9d %9d %9d %9d", + nfsstats.biocache_readlinks-nfsstats.readlink_bios, + nfsstats.readlink_bios, + nfsstats.biocache_readdirs-nfsstats.readdir_bios, + nfsstats.readdir_bios); + printf(" %9d %9d\n", + nfsstats.direofcache_hits, nfsstats.direofcache_misses); + printf("\nServer Info:\n"); + printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", + "Getattr", "Setattr", "Lookup", "Readlink", "Read", + "Write", "Create", "Remove"); + printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", + nfsstats.srvrpccnt[NFSPROC_GETATTR], + nfsstats.srvrpccnt[NFSPROC_SETATTR], + nfsstats.srvrpccnt[NFSPROC_LOOKUP], + nfsstats.srvrpccnt[NFSPROC_READLINK], + nfsstats.srvrpccnt[NFSPROC_READ], + nfsstats.srvrpccnt[NFSPROC_WRITE], + nfsstats.srvrpccnt[NFSPROC_CREATE], + nfsstats.srvrpccnt[NFSPROC_REMOVE]); + printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", + "Rename", "Link", "Symlink", "Mkdir", "Rmdir", + "Readdir", "Statfs", "RdirLook"); + printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", + nfsstats.srvrpccnt[NFSPROC_RENAME], + nfsstats.srvrpccnt[NFSPROC_LINK], + nfsstats.srvrpccnt[NFSPROC_SYMLINK], + nfsstats.srvrpccnt[NFSPROC_MKDIR], + nfsstats.srvrpccnt[NFSPROC_RMDIR], + nfsstats.srvrpccnt[NFSPROC_READDIR], + nfsstats.srvrpccnt[NFSPROC_STATFS], + nfsstats.srvrpccnt[NQNFSPROC_READDIRLOOK]); + printf("%9.9s %9.9s %9.9s\n", + "GLease", "Vacate", "Evict"); + printf("%9d %9d %9d\n", + nfsstats.srvrpccnt[NQNFSPROC_GETLEASE], + nfsstats.srvrpccnt[NQNFSPROC_VACATED], + nfsstats.srvrpccnt[NQNFSPROC_EVICTED]); + printf("Server Ret-Failed\n"); + printf("%17d\n", nfsstats.srvrpc_errs); + printf("Server Faults\n"); + printf("%13d\n", nfsstats.srv_errs); + printf("Server Cache Stats:\n"); + printf("%9.9s %9.9s %9.9s %9.9s\n", + "Inprog", "Idem", "Non-idem", "Misses"); + printf("%9d %9d %9d %9d\n", + nfsstats.srvcache_inproghits, + nfsstats.srvcache_idemdonehits, + nfsstats.srvcache_nonidemdonehits, + nfsstats.srvcache_misses); + printf("Server Lease Stats:\n"); + printf("%9.9s %9.9s %9.9s\n", + "Leases", "PeakL", "GLeases"); + printf("%9d %9d %9d\n", + nfsstats.srvnqnfs_leases, + nfsstats.srvnqnfs_maxleases, + nfsstats.srvnqnfs_getleases); +} + +u_char signalled; /* set if alarm goes off "early" */ + +/* + * Print a running summary of nfs 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. + */ +void +sidewaysintpr(interval, off) + u_int interval; + u_long off; +{ + struct nfsstats nfsstats, lastst; + int hdrcnt, oldmask; + void catchalarm(); + + (void)signal(SIGALRM, catchalarm); + signalled = 0; + (void)alarm(interval); + bzero((caddr_t)&lastst, sizeof(lastst)); + + for (hdrcnt = 1;;) { + if (!--hdrcnt) { + printhdr(); + hdrcnt = 20; + } + if (kvm_read(kd, off, (char *)&nfsstats, sizeof nfsstats) < 0) { + fprintf(stderr, "nfsstat: kvm_read failed\n"); + exit(1); + } + printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n", + nfsstats.rpccnt[1]-lastst.rpccnt[1], + nfsstats.rpccnt[4]-lastst.rpccnt[4], + nfsstats.rpccnt[5]-lastst.rpccnt[5], + nfsstats.rpccnt[6]-lastst.rpccnt[6], + nfsstats.rpccnt[8]-lastst.rpccnt[8], + nfsstats.rpccnt[11]-lastst.rpccnt[11], + nfsstats.rpccnt[12]-lastst.rpccnt[12], + nfsstats.rpccnt[16]-lastst.rpccnt[16]); + printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n", + nfsstats.srvrpccnt[1]-lastst.srvrpccnt[1], + nfsstats.srvrpccnt[4]-lastst.srvrpccnt[4], + nfsstats.srvrpccnt[5]-lastst.srvrpccnt[5], + nfsstats.srvrpccnt[6]-lastst.srvrpccnt[6], + nfsstats.srvrpccnt[8]-lastst.srvrpccnt[8], + nfsstats.srvrpccnt[11]-lastst.srvrpccnt[11], + nfsstats.srvrpccnt[12]-lastst.srvrpccnt[12], + nfsstats.srvrpccnt[16]-lastst.srvrpccnt[16]); + lastst = nfsstats; + fflush(stdout); + oldmask = sigblock(sigmask(SIGALRM)); + if (!signalled) + sigpause(0); + sigsetmask(oldmask); + signalled = 0; + (void)alarm(interval); + } + /*NOTREACHED*/ +} + +void +printhdr() +{ + printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", + "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", + "Link", "Readdir"); + fflush(stdout); +} + +/* + * Called if an interval expires before sidewaysintpr has completed a loop. + * Sets a flag to not wait for the alarm. + */ +void +catchalarm() +{ + signalled = 1; +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: nfsstat [-M core] [-N system] [-w interval]\n"); + exit(1); +} diff --git a/usr.bin/nice/Makefile b/usr.bin/nice/Makefile new file mode 100644 index 0000000..d36378e --- /dev/null +++ b/usr.bin/nice/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= nice + +.include diff --git a/usr.bin/nice/nice.1 b/usr.bin/nice/nice.1 new file mode 100644 index 0000000..67b8471 --- /dev/null +++ b/usr.bin/nice/nice.1 @@ -0,0 +1,97 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)nice.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt NICE 1 +.Os BSD 4 +.Sh NAME +.Nm nice +.Nd execute a command at a low scheduling priority +.Sh SYNOPSIS +.Nm nice +.Op Fl Ns Ar number +.Ar command +.Op Ar arguments +.Sh DESCRIPTION +.Nm Nice +runs +.Ar command +at a low priority. +(Think of low and slow). +If +.Fl Ns Ar number +is specified, and if it is greater than or equal +to 10 (the default), +.Nm nice +will execute +.Ar command +at that priority. +The upper bound, or lowest priority that +.Nm nice +will run a command is 20. +The lower bounds or +higher priorities (integers less than 10) +can only be requested by the super-user. +Negative numbers are expressed as +.Fl - Ns Ar number . +.Pp +The returned exit status is the exit value from the +command executed by +.Nm nice . +.Sh SEE ALSO +.Xr csh 1 , +.Xr renice 8 +.Sh HISTORY +A +.Nm nice +command appeared in +.At v6 . +.Sh BUGS +.Nm Nice +is particular to +.Xr sh 1 . +If you use +.Xr csh 1 , +then commands executed with ``&'' are automatically immune to hangup +signals while in the background. +.Pp +.Nm Nice +is built into +.Xr csh 1 +with a slightly different syntax than described here. The form +.Ql nice +10 +nices to positive nice, and +.Ql nice \-10 +can be used +by the super-user to give a process more of the processor. diff --git a/usr.bin/nice/nice.c b/usr.bin/nice/nice.c new file mode 100644 index 0000000..6b905d9 --- /dev/null +++ b/usr.bin/nice/nice.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)nice.c 8.2 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEFNICE 10 + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int niceness = DEFNICE; + + if (argv[1][0] == '-') + if (argv[1][1] == '-' || isdigit(argv[1][1])) { + niceness = atoi(argv[1] + 1); + ++argv; + } else + errx(1, "illegal option -- %s", argv[1]); + + if (argv[1] == NULL) + usage(); + + errno = 0; + niceness += getpriority(PRIO_PROCESS, 0); + if (errno) + err(1, "getpriority"); + if (setpriority(PRIO_PROCESS, 0, niceness)) + err(1, "setpriority"); + execvp(argv[1], &argv[1]); + err(1, "%s", argv[1]); +} + +void +usage() +{ + (void)fprintf(stderr, + "nice [ -# ] command [ options ] [ operands ]\n"); + exit(1); +} diff --git a/usr.bin/nm/Makefile b/usr.bin/nm/Makefile new file mode 100644 index 0000000..5266202 --- /dev/null +++ b/usr.bin/nm/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= nm + +.include diff --git a/usr.bin/nm/nm.1 b/usr.bin/nm/nm.1 new file mode 100644 index 0000000..ff7cdb2 --- /dev/null +++ b/usr.bin/nm/nm.1 @@ -0,0 +1,117 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)nm.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt NM 1 +.Os BSD 4 +.Sh NAME +.Nm nm +.Nd display name list (symbol table) +.Sh SYNOPSIS +.Nm nm +.Op Fl agnopruw +.Ar +.Sh DESCRIPTION +The symbol table (name list) of each object in +.Ar file(s) +is displayed. +If a library (archive) is given, +.Nm +displays a list for each +object archive member. +If +.Ar file +is not present, +.Nm +searches for the file +.Pa a.out +and if present, displays the symbol +table for +.Pa a.out . +.Bl -tag -width flag +.It Fl a +Display symbol table entries inserted for use by debuggers. +.It Fl g +Restrict display to external (global) symbols. +.It Fl n +Present results in numerical order. +.It Fl o +Display full path or library name of object on every line. +.It Fl p +Do not sort at all. +.It Fl r +Reverse order sort. +.It Fl u +Display undefined symbols only. +.It Fl w +Warn about non-object archive members. +Normally, nm will silently ignore all archive members which are not +object files. +.El +.Pp +Each symbol name is preceded by its value (a blank field if the symbol +is undefined) and one of the following letters: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Fl +debugger symbol table entries (see the +.Fl a +option). +.It Li A +absolute +.It Li B +bss segment symbol +.It Li C +common symbol +.It Li D +data segment symbol +.It Li f +file name +.It Li T +text segment symbol +.It Li U +undefined +.El +.Pp +If the symbol is local (non-external) the type letter is in lower case. +The output is sorted alphabetically. +.Sh SEE ALSO +.Xr ar 1 , +.Xr ar 5 , +.Xr a.out 5 , +.Xr stab 5 +.Sh HISTORY +An +.Nm nm +command appeared in +.At v6 . diff --git a/usr.bin/nm/nm.c b/usr.bin/nm/nm.c new file mode 100644 index 0000000..6744cf6 --- /dev/null +++ b/usr.bin/nm/nm.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hans Huebner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int ignore_bad_archive_entries = 1; +int print_only_external_symbols; +int print_only_undefined_symbols; +int print_all_symbols; +int print_file_each_line; +int fcount; + +int rev; +int fname(), rname(), value(); +int (*sfunc)() = fname; + +/* some macros for symbol type (nlist.n_type) handling */ +#define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB) +#define IS_EXTERNAL(x) ((x) & N_EXT) +#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) + +void *emalloc(); + +/* + * main() + * parse command line, execute process_file() for each file + * specified on the command line. + */ +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + int ch, errors; + + while ((ch = getopt(argc, argv, "agnopruw")) != EOF) { + switch (ch) { + case 'a': + print_all_symbols = 1; + break; + case 'g': + print_only_external_symbols = 1; + break; + case 'n': + sfunc = value; + break; + case 'o': + print_file_each_line = 1; + break; + case 'p': + sfunc = NULL; + break; + case 'r': + rev = 1; + break; + case 'u': + print_only_undefined_symbols = 1; + break; + case 'w': + ignore_bad_archive_entries = 0; + break; + case '?': + default: + usage(); + } + } + fcount = argc - optind; + argv += optind; + + if (rev && sfunc == fname) + sfunc = rname; + + if (!fcount) + errors = process_file("a.out"); + else { + errors = 0; + do { + errors |= process_file(*argv); + } while (*++argv); + } + exit(errors); +} + +/* + * process_file() + * show symbols in the file given as an argument. Accepts archive and + * object files as input. + */ +process_file(fname) + char *fname; +{ + struct exec exec_head; + FILE *fp; + int retval; + char magic[SARMAG]; + + if (!(fp = fopen(fname, "r"))) { + (void)fprintf(stderr, "nm: cannot read %s.\n", fname); + return(1); + } + + if (fcount > 1) + (void)printf("\n%s:\n", fname); + + /* + * first check whether this is an object file - read a object + * header, and skip back to the beginning + */ + if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) { + (void)fprintf(stderr, "nm: %s: bad format.\n", fname); + (void)fclose(fp); + return(1); + } + rewind(fp); + + /* this could be an archive */ + if (N_BADMAG(exec_head)) { + if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || + strncmp(magic, ARMAG, SARMAG)) { + (void)fprintf(stderr, + "nm: %s: not object file or archive.\n", fname); + (void)fclose(fp); + return(1); + } + retval = show_archive(fname, fp); + } else + retval = show_objfile(fname, fp); + (void)fclose(fp); + return(retval); +} + +/* + * show_archive() + * show symbols in the given archive file + */ +show_archive(fname, fp) + char *fname; + FILE *fp; +{ + struct ar_hdr ar_head; + struct exec exec_head; + int i, rval; + long last_ar_off; + char *p, *name; + + name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3); + + rval = 0; + + /* while there are more entries in the archive */ + while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) { + /* bad archive entry - stop processing this archive */ + if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { + (void)fprintf(stderr, + "nm: %s: bad format archive header", fname); + (void)free(name); + return(1); + } + + /* remember start position of current archive object */ + last_ar_off = ftell(fp); + + /* skip ranlib entries */ + if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1)) + goto skip; + + /* + * construct a name of the form "archive.a:obj.o:" for the + * current archive entry if the object name is to be printed + * on each output line + */ + p = name; + if (print_file_each_line) + p += sprintf(p, "%s:", fname); + for (i = 0; i < sizeof(ar_head.ar_name); ++i) + if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ') + *p++ = ar_head.ar_name[i]; + *p++ = '\0'; + + /* get and check current object's header */ + if (fread((char *)&exec_head, sizeof(exec_head), + (size_t)1, fp) != 1) { + (void)fprintf(stderr, "nm: %s: premature EOF.\n", name); + (void)free(name); + return(1); + } + + if (N_BADMAG(exec_head)) { + if (!ignore_bad_archive_entries) { + (void)fprintf(stderr, + "nm: %s: bad format.\n", name); + rval = 1; + } + } else { + (void)fseek(fp, (long)-sizeof(exec_head), + SEEK_CUR); + if (!print_file_each_line) + (void)printf("\n%s:\n", name); + rval |= show_objfile(name, fp); + } + + /* + * skip to next archive object - it starts at the next + * even byte boundary + */ +#define even(x) (((x) + 1) & ~1) +skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)), + SEEK_SET)) { + (void)fprintf(stderr, + "nm: %s: %s\n", fname, strerror(errno)); + (void)free(name); + return(1); + } + } + (void)free(name); + return(rval); +} + +/* + * show_objfile() + * show symbols from the object file pointed to by fp. The current + * file pointer for fp is expected to be at the beginning of an a.out + * header. + */ +show_objfile(objname, fp) + char *objname; + FILE *fp; +{ + register struct nlist *names, *np; + register int i, nnames, nrawnames; + struct exec head; + long stabsize; + char *stab; + + /* read a.out header */ + if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) { + (void)fprintf(stderr, + "nm: %s: cannot read header.\n", objname); + return(1); + } + + /* + * skip back to the header - the N_-macros return values relative + * to the beginning of the a.out header + */ + if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) { + (void)fprintf(stderr, + "nm: %s: %s\n", objname, strerror(errno)); + return(1); + } + + /* stop if this is no valid object file */ + if (N_BADMAG(head)) { + (void)fprintf(stderr, + "nm: %s: bad format.\n", objname); + return(1); + } + + /* stop if the object file contains no symbol table */ + if (!head.a_syms) { + (void)fprintf(stderr, + "nm: %s: no name list.\n", objname); + return(1); + } + + if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) { + (void)fprintf(stderr, + "nm: %s: %s\n", objname, strerror(errno)); + return(1); + } + + /* get memory for the symbol table */ + names = emalloc((size_t)head.a_syms); + nrawnames = head.a_syms / sizeof(*names); + if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) { + (void)fprintf(stderr, + "nm: %s: cannot read symbol table.\n", objname); + (void)free((char *)names); + return(1); + } + + /* + * Following the symbol table comes the string table. The first + * 4-byte-integer gives the total size of the string table + * _including_ the size specification itself. + */ + if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) { + (void)fprintf(stderr, + "nm: %s: cannot read stab size.\n", objname); + (void)free((char *)names); + return(1); + } + stab = emalloc((size_t)stabsize); + + /* + * read the string table offset by 4 - all indices into the string + * table include the size specification. + */ + stabsize -= 4; /* we already have the size */ + if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) { + (void)fprintf(stderr, + "nm: %s: stab truncated..\n", objname); + (void)free((char *)names); + (void)free(stab); + return(1); + } + + /* + * fix up the symbol table and filter out unwanted entries + * + * common symbols are characterized by a n_type of N_UNDF and a + * non-zero n_value -- change n_type to N_COMM for all such + * symbols to make life easier later. + * + * filter out all entries which we don't want to print anyway + */ + for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { + if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value) + np->n_type = N_COMM | (np->n_type & N_EXT); + if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type)) + continue; + if (print_only_external_symbols && !IS_EXTERNAL(np->n_type)) + continue; + if (print_only_undefined_symbols && + SYMBOL_TYPE(np->n_type) != N_UNDF) + continue; + + /* + * make n_un.n_name a character pointer by adding the string + * table's base to n_un.n_strx + * + * don't mess with zero offsets + */ + if (np->n_un.n_strx) + np->n_un.n_name = stab + np->n_un.n_strx; + else + np->n_un.n_name = ""; + names[nnames++] = *np; + } + + /* sort the symbol table if applicable */ + if (sfunc) + qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc); + + /* print out symbols */ + for (np = names, i = 0; i < nnames; np++, i++) + print_symbol(objname, np); + + (void)free((char *)names); + (void)free(stab); + return(0); +} + +/* + * print_symbol() + * show one symbol + */ +print_symbol(objname, sym) + char *objname; + register struct nlist *sym; +{ + char *typestring(), typeletter(); + + if (print_file_each_line) + (void)printf("%s:", objname); + + /* + * handle undefined-only format seperately (no space is + * left for symbol values, no type field is printed) + */ + if (print_only_undefined_symbols) { + (void)puts(sym->n_un.n_name); + return; + } + + /* print symbol's value */ + if (SYMBOL_TYPE(sym->n_type) == N_UNDF) + (void)printf(" "); + else + (void)printf("%08lx", sym->n_value); + + /* print type information */ + if (IS_DEBUGGER_SYMBOL(sym->n_type)) + (void)printf(" - %02x %04x %5s ", sym->n_other, + sym->n_desc&0xffff, typestring(sym->n_type)); + else + (void)printf(" %c ", typeletter(sym->n_type)); + + /* print the symbol's name */ + (void)puts(sym->n_un.n_name); +} + +/* + * typestring() + * return the a description string for an STAB entry + */ +char * +typestring(type) + register u_char type; +{ + switch(type) { + case N_BCOMM: + return("BCOMM"); + case N_ECOML: + return("ECOML"); + case N_ECOMM: + return("ECOMM"); + case N_ENTRY: + return("ENTRY"); + case N_FNAME: + return("FNAME"); + case N_FUN: + return("FUN"); + case N_GSYM: + return("GSYM"); + case N_LBRAC: + return("LBRAC"); + case N_LCSYM: + return("LCSYM"); + case N_LENG: + return("LENG"); + case N_LSYM: + return("LSYM"); + case N_PC: + return("PC"); + case N_PSYM: + return("PSYM"); + case N_RBRAC: + return("RBRAC"); + case N_RSYM: + return("RSYM"); + case N_SLINE: + return("SLINE"); + case N_SO: + return("SO"); + case N_SOL: + return("SOL"); + case N_SSYM: + return("SSYM"); + case N_STSYM: + return("STSYM"); + } + return("???"); +} + +/* + * typeletter() + * return a description letter for the given basic type code of an + * symbol table entry. The return value will be upper case for + * external, lower case for internal symbols. + */ +char +typeletter(type) + u_char type; +{ + switch(SYMBOL_TYPE(type)) { + case N_ABS: + return(IS_EXTERNAL(type) ? 'A' : 'a'); + case N_BSS: + return(IS_EXTERNAL(type) ? 'B' : 'b'); + case N_COMM: + return(IS_EXTERNAL(type) ? 'C' : 'c'); + case N_DATA: + return(IS_EXTERNAL(type) ? 'D' : 'd'); + case N_FN: + return(IS_EXTERNAL(type) ? 'F' : 'f'); + case N_TEXT: + return(IS_EXTERNAL(type) ? 'T' : 't'); + case N_UNDF: + return(IS_EXTERNAL(type) ? 'U' : 'u'); + } + return('?'); +} + +fname(a0, b0) + void *a0, *b0; +{ + struct nlist *a = a0, *b = b0; + + return(strcmp(a->n_un.n_name, b->n_un.n_name)); +} + +rname(a0, b0) + void *a0, *b0; +{ + struct nlist *a = a0, *b = b0; + + return(strcmp(b->n_un.n_name, a->n_un.n_name)); +} + +value(a0, b0) + void *a0, *b0; +{ + register struct nlist *a = a0, *b = b0; + + if (SYMBOL_TYPE(a->n_type) == N_UNDF) + if (SYMBOL_TYPE(b->n_type) == N_UNDF) + return(0); + else + return(-1); + else if (SYMBOL_TYPE(b->n_type) == N_UNDF) + return(1); + if (rev) { + if (a->n_value == b->n_value) + return(rname(a0, b0)); + return(b->n_value > a->n_value ? 1 : -1); + } else { + if (a->n_value == b->n_value) + return(fname(a0, b0)); + return(a->n_value > b->n_value ? 1 : -1); + } +} + +void * +emalloc(size) + size_t size; +{ + char *p; + + /* NOSTRICT */ + if (p = malloc(size)) + return(p); + (void)fprintf(stderr, "nm: %s\n", strerror(errno)); + exit(1); +} + +usage() +{ + (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/nohup/Makefile b/usr.bin/nohup/Makefile new file mode 100644 index 0000000..c072a27 --- /dev/null +++ b/usr.bin/nohup/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= nohup + +.include diff --git a/usr.bin/nohup/nohup.1 b/usr.bin/nohup/nohup.1 new file mode 100644 index 0000000..d04e486 --- /dev/null +++ b/usr.bin/nohup/nohup.1 @@ -0,0 +1,90 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)nohup.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt NOHUP 1 +.Os +.Sh NAME +.Nm nohup +.Nd invoke a command immune to hangups +.Sh SYNOPSIS +.Nm nohup +.Ar command +.Op Ar arg ... +.Sh DESCRIPTION +The +.Nm nohup +utility invokes +.Ar command +with +its arguments +and at this time sets the signal +.Dv SIGHUP +to be ignored. The signal +.Dv SIGQUIT +may also be set +to be ignored. +If the standard output is a terminal, the standard output is +appended to the file +.Pa nohup.out +in the current directory. +If standard error is a terminal, it is directed to the same place +as the standard output. +.Pp +.Nm Nohup +exits 1 if an error occurs, otherwise the exit status is that of +.Ar command . +.Sh ENVIRONMENT +The following variable is utilized by +.Nm nohup . +.Bl -tag -width flag +.It Ev HOME +If the output file +.Pa nohup.out +cannot be created in the current directory, the +.Nm nohup +utility uses the directory named by +.Ev HOME +to create the file. +.El +.Sh SEE ALSO +.Xr signal 3 +.Sh STANDARDS +The +.Nm nohup +command is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/nohup/nohup.c b/usr.bin/nohup/nohup.c new file mode 100644 index 0000000..d469a13 --- /dev/null +++ b/usr.bin/nohup/nohup.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)nohup.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void dofile __P((void)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + if (argc < 2) + usage(); + + if (isatty(STDOUT_FILENO)) + dofile(); + if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + /* may have just closed stderr */ + (void)fprintf(stdin, "nohup: %s\n", strerror(errno)); + exit(1); + } + + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + + execvp(argv[1], &argv[1]); + (void)fprintf(stderr, + "nohup: %s: %s\n", argv[1], strerror(errno)); + exit(1); +} + +void +dofile() +{ + int fd; + char *p, path[MAXPATHLEN]; + +#define FILENAME "nohup.out" + p = FILENAME; + if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR)) >= 0) + goto dupit; + if (p = getenv("HOME")) { + (void)strcpy(path, p); + (void)strcat(path, "/"); + (void)strcat(path, FILENAME); + if ((fd = open(p = path, + O_RDWR|O_CREAT, S_IRUSR | S_IWUSR)) >= 0) + goto dupit; + } + (void)fprintf(stderr, "nohup: can't open a nohup.out file.\n"); + exit(1); + +dupit: (void)lseek(fd, (off_t)0, SEEK_END); + if (dup2(fd, STDOUT_FILENO) == -1) { + (void)fprintf(stderr, "nohup: %s\n", strerror(errno)); + exit(1); + } + (void)fprintf(stderr, "sending output to %s\n", p); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: nohup command\n"); + exit(1); +} diff --git a/usr.bin/pagesize/Makefile b/usr.bin/pagesize/Makefile new file mode 100644 index 0000000..0a4d652 --- /dev/null +++ b/usr.bin/pagesize/Makefile @@ -0,0 +1,17 @@ +# @(#)Makefile 8.2 (Berkeley) 4/3/94 + +MAN1= pagesize.0 + +all pagesize: ${MAN1} + +clean depend lint tags: + +cleandir: + rm -f ${MAN1} + +install: maninstall + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/pagesize.sh ${DESTDIR}/${BINDIR}/pagesize + +.include +.include diff --git a/usr.bin/pagesize/pagesize.1 b/usr.bin/pagesize/pagesize.1 new file mode 100644 index 0000000..4beec29 --- /dev/null +++ b/usr.bin/pagesize/pagesize.1 @@ -0,0 +1,56 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)pagesize.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PAGESIZE 1 +.Os BSD 4.2 +.Sh NAME +.Nm pagesize +.Nd print system page size +.Sh SYNOPSIS +.Nm pagesize +.Sh DESCRIPTION +.Nm Pagesize +prints the size of a page of memory in bytes, as +returned by +.Xr getpagesize 2 . +This program is useful in constructing portable +shell scripts. +.Sh SEE ALSO +.Xr getpagesize 2 +.Sh HISTORY +The +.Nm pagesize +command +appeared in +.Bx 4.2 . diff --git a/usr.bin/pagesize/pagesize.sh b/usr.bin/pagesize/pagesize.sh new file mode 100644 index 0000000..da22179 --- /dev/null +++ b/usr.bin/pagesize/pagesize.sh @@ -0,0 +1,40 @@ +#!/bin/sh - +# +# 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. +# +# @(#)pagesize.sh 8.1 (Berkeley) 4/3/94 +# + +PATH=/bin:/usr/bin:/usr/sbin +export PATH + +sysctl -n hw.pagesize diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile new file mode 100644 index 0000000..8681573 --- /dev/null +++ b/usr.bin/passwd/Makefile @@ -0,0 +1,15 @@ +# @(#)Makefile 8.3 (Berkeley) 4/2/94 + +PROG= passwd +SRCS= des_rw.c krb_passwd.c local_passwd.c passwd.c pw_copy.c pw_util.c +DPADD= ${LIBKRB} ${LIBDES} +.PATH: ${.CURDIR}/../../usr.bin/chpass ${.CURDIR}/../../usr.sbin/vipw \ + ${.CURDIR}/../rlogin +CFLAGS+=-DKERBEROS -DCRYPT -I${.CURDIR} -I${.CURDIR}/../../usr.sbin/vipw \ + -I${.CURDIR}/../../usr.bin/chpass +LDADD= -lkrb -ldes +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg + +.include diff --git a/usr.bin/passwd/extern.h b/usr.bin/passwd/extern.h new file mode 100644 index 0000000..67d6dee --- /dev/null +++ b/usr.bin/passwd/extern.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 4/2/94 + */ + +int krb_passwd __P((void)); +int local_passwd __P((char *)); diff --git a/usr.bin/passwd/kpasswd_proto.h b/usr.bin/passwd/kpasswd_proto.h new file mode 100644 index 0000000..465d4c7 --- /dev/null +++ b/usr.bin/passwd/kpasswd_proto.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1989, 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. + * + * @(#)kpasswd_proto.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * 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 0000000..d4a0f15 --- /dev/null +++ b/usr.bin/passwd/krb_passwd.c @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)krb_passwd.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#ifdef KERBEROS + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kpasswd_proto.h" + +#include "extern.h" + +#define PROTO "tcp" + +static void send_update __P((int, char *, char *)); +static void recv_ack __P((int)); +static void cleanup __P((void)); +static void finish __P((void)); + +static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 }; +static struct kpasswd_data proto_data; +static des_cblock okey; +static Key_schedule osched; +static KTEXT_ST ticket; +static Key_schedule random_schedule; +static long authopts; +static char realm[REALM_SZ], krbhst[MAX_HSTNM]; +static int sock; + +int +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) { + warn("setrlimit"); + return (1); + } + + if ((se = getservbyname(SERVICE, PROTO)) == NULL) { + warnx("couldn't find entry for service %s/%s", + SERVICE, PROTO); + return (1); + } + + if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) { + warnx("couldn't get local Kerberos realm: %s", + krb_err_txt[rval]); + return (1); + } + + if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) { + warnx("couldn't get Kerberos host: %s", + krb_err_txt[rval]); + return (1); + } + + if ((host = gethostbyname(krbhst)) == NULL) { + warnx("couldn't get host entry for krb host %s", + krbhst); + return (1); + } + + sin.sin_family = host->h_addrtype; + memmove((char *) &sin.sin_addr, host->h_addr, host->h_length); + sin.sin_port = se->s_port; + + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + warn("socket"); + return (1); + } + + if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + warn("connect"); + (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) { + warnx("Kerberos sendauth error: %s", 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)) { + warnx("error reading old Kerberos password"); + 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) { + warnx("timed out (aborted)"); + cleanup(); + return (1); + } + warnx("select failed (aborted)"); + cleanup(); + return (1); + } + + /* read verification string */ + + if (des_read(sock, &proto_data, sizeof(proto_data)) != + sizeof(proto_data)) { + warnx("couldn't read verification string (aborted)"); + 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)memset(pass, 0, sizeof(pass)); + + if (des_read_pw_string(pass, + sizeof(pass)-1, "New Kerberos password:", 0)) { + warnx("error reading new Kerberos password (aborted)"); + cleanup(); + return (1); + } + + if (des_read_pw_string(password, + sizeof(password)-1, "Retype new Kerberos password:", 0)) { + warnx("error reading new Kerberos password (aborted)"); + cleanup(); + return (1); + } + + if (strcmp(password, pass) != 0) { + warnx("password mismatch (aborted)"); + 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) { + warnx("timed out reading ACK (aborted)"); + cleanup(); + exit(1); + } + warnx("select failed (aborted)"); + cleanup(); + exit(1); + } + recv_ack(sock); + cleanup(); + return (0); +} + +static void +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)) { + warnx("couldn't write pw update (abort)"); + memset((char *)&ud, 0, sizeof(ud)); + cleanup(); + exit(1); + } +} + +static void +recv_ack(remote) + int remote; +{ + int cc; + char buf[BUFSIZ]; + + cc = des_read(remote, buf, sizeof(buf)); + if (cc <= 0) { + warnx("error reading acknowledgement (aborted)"); + cleanup(); + exit(1); + } + (void)printf("%s", buf); +} + +static void +cleanup() +{ + + (void)memset((char *)&proto_data, 0, sizeof(proto_data)); + (void)memset((char *)okey, 0, sizeof(okey)); + (void)memset((char *)osched, 0, sizeof(osched)); + (void)memset((char *)random_schedule, 0, 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 new file mode 100644 index 0000000..804c48e --- /dev/null +++ b/usr.bin/passwd/local_passwd.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "extern.h" + +static uid_t uid; + +char *tempname; + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void +to64(s, v, n) + char *s; + long v; + int n; +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +char * +getnewpasswd(pw) + struct passwd *pw; +{ + int tries; + char *p, *t; + char buf[_PASSWORD_LEN+1], salt[9]; + + (void)printf("Changing local password for %s.\n", pw->pw_name); + + if (uid && pw->pw_passwd[0] && + strcmp(crypt(getpass("Old password:"), pw->pw_passwd), + pw->pw_passwd)) { + errno = EACCES; + pw_error(NULL, 1, 1); + } + + for (buf[0] = '\0', tries = 0;;) { + p = getpass("New password:"); + if (!*p) { + (void)printf("Password unchanged.\n"); + pw_error(NULL, 0, 0); + } + if (strlen(p) <= 5 && (uid != 0 || ++tries < 2)) { + (void)printf("Please enter a longer password.\n"); + continue; + } + for (t = p; *t && islower(*t); ++t); + if (!*t && (uid != 0 || ++tries < 2)) { + (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); + continue; + } + (void)strcpy(buf, p); + if (!strcmp(buf, getpass("Retype new password:"))) + break; + (void)printf("Mismatch; try again, EOF to quit.\n"); + } + /* grab a random printable character that isn't a colon */ + (void)srandom((int)time((time_t *)NULL)); +#ifdef NEWSALT + salt[0] = _PASSWORD_EFMT1; + to64(&salt[1], (long)(29 * 25), 4); + to64(&salt[5], random(), 4); +#else + to64(&salt[0], random(), 2); +#endif + return (crypt(buf, salt)); +} + +int +local_passwd(uname) + char *uname; +{ + struct passwd *pw; + int pfd, tfd; + + if (!(pw = getpwnam(uname))) + errx(1, "unknown user %s", uname); + + uid = getuid(); + if (uid && uid != pw->pw_uid) + errx(1, "%s", strerror(EACCES)); + + pw_init(); + pfd = pw_lock(); + tfd = pw_tmp(); + + /* + * Get the new password. Reset passwd change time to zero; when + * classes are implemented, go and get the "offset" value for this + * class and reset the timer. + */ + pw->pw_passwd = getnewpasswd(pw); + pw->pw_change = 0; + pw_copy(pfd, tfd, pw); + + if (!pw_mkdb()) + pw_error((char *)NULL, 0, 1); + return (0); +} diff --git a/usr.bin/passwd/passwd.1 b/usr.bin/passwd/passwd.1 new file mode 100644 index 0000000..4b07f93 --- /dev/null +++ b/usr.bin/passwd/passwd.1 @@ -0,0 +1,107 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)passwd.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PASSWD 1 +.Os BSD 4 +.Sh NAME +.Nm passwd +.Nd modify a user's password +.Sh SYNOPSIS +.Nm passwd +.Op Fl l +.Op Ar user +.Sh DESCRIPTION +.Nm Passwd +changes the user's Kerberos password. First, the user is prompted for their +current password. +If the current password is correctly typed, a new password is +requested. +The new password must be entered twice to avoid typing errors. +.Pp +The new password should be at least six characters long and not +purely alphabetic. +Its total length must be less than +.Dv _PASSWORD_LEN +(currently 128 characters). +Numbers, upper case letters and meta characters +are encouraged. +.Pp +Once the password has been verified, +.Nm passwd +communicates the new password information to +the Kerberos authenticating host. +.Bl -tag -width flag +.It Fl l +This option causes the password to be updated only in the local +password file, and not with the Kerberos database. +When changing only the local password, +.Xr pwd_mkdb 8 +is used to update the password databases. +.El +.Pp +To change another user's Kerberos password, one must first +run +.Xr kinit 1 +followed by +.Xr passwd 1 . +The super-user is not required to provide a user's current password +if only the local password is modified. +.Sh FILES +.Bl -tag -width /etc/master.passwd -compact +.It Pa /etc/master.passwd +The user database +.It Pa /etc/passwd +A Version 7 format password file +.It Pa /etc/passwd.XXXXXX +Temporary copy of the password file +.El +.Sh SEE ALSO +.Xr chpass 1 , +.Xr kerberos 1 , +.Xr kinit 1 , +.Xr login 1 , +.Xr passwd 5 , +.Xr kpasswdd 8 , +.Xr pwd_mkdb 8 , +.Xr vipw 8 +.Rs +.%A Robert Morris +.%A Ken Thompson +.%T "UNIX password security" +.Re +.Sh HISTORY +A +.Nm passwd +command appeared in +.At v6 . diff --git a/usr.bin/passwd/passwd.c b/usr.bin/passwd/passwd.c new file mode 100644 index 0000000..8615ab5 --- /dev/null +++ b/usr.bin/passwd/passwd.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)passwd.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include "extern.h" + +void usage __P((void)); + +#ifdef KERBEROS +int use_kerberos = 1; +#endif + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + char *uname; + + while ((ch = getopt(argc, argv, "l")) != EOF) + switch (ch) { +#ifdef KERBEROS + case 'l': /* change local password file */ + use_kerberos = 0; + break; +#endif + default: + case '?': + usage(); + } + + argc -= optind; + argv += optind; + + if ((uname = getlogin()) == NULL) + err(1, "getlogin"); + + switch(argc) { + case 0: + break; + case 1: +#ifdef KERBEROS + if (use_kerberos && strcmp(argv[0], uname)) + errx(1,"%s\n\t%s\n%s\n", + "to change another user's Kerberos password, do", + "\"kinit user; passwd; kdestroy\";", + "to change a user's local passwd, use \"passwd -l user\""); +#endif + uname = argv[0]; + break; + default: + usage(); + } + +#ifdef KERBEROS + if (use_kerberos) + exit(krb_passwd()); +#endif + exit(local_passwd(uname)); +} + +void +usage() +{ + +#ifdef KERBEROS + (void)fprintf(stderr, "usage: passwd [-l] user\n"); +#else + (void)fprintf(stderr, "usage: passwd user\n"); +#endif + exit(1); +} diff --git a/usr.bin/paste/Makefile b/usr.bin/paste/Makefile new file mode 100644 index 0000000..aa237fb --- /dev/null +++ b/usr.bin/paste/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= paste + +.include diff --git a/usr.bin/paste/paste.1 b/usr.bin/paste/paste.1 new file mode 100644 index 0000000..f62b994 --- /dev/null +++ b/usr.bin/paste/paste.1 @@ -0,0 +1,119 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Adam S. Moskowitz and the Institute of Electrical and Electronics +.\" Engineers, 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. +.\" +.\" @(#)paste.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PASTE 1 +.Os +.Sh NAME +.Nm paste +.Nd merge corresponding or subsequent lines of files +.Sh SYNOPSIS +.Nm paste +.Op Fl s +.Op Fl d Ar list +.Ar file ... +.Sh DESCRIPTION +The +.Nm paste +utility concatenates the corresponding lines of the given input files, +replacing all but the last file's newline characters with a single tab +character, and writes the resulting lines to standard output. +If end-of-file is reached on an input file while other input files +still contain data, the file is treated as if it were an endless source +of empty lines. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl d Ar list +Use one or more of the provided characters to replace the newline +characters instead of the default tab. +The characters in +.Ar list +are used circularly, i.e., when +.Ar list +is exhausted the first character from +.Ar list +is reused. +This continues until a line from the last input file (in default operation) +or the last line in each file (using the -s option) is displayed, at which +time +.Nm paste +begins selecting characters from the beginning of +.Ar list +again. +.Pp +The following special characters can also be used in list: +.Pp +.Bl -tag -width flag -compact +.It Li \en +newline character +.It Li \et +tab character +.It Li \e\e +backslash character +.It Li \e0 +Empty string (not a null character). +.El +.Pp +Any other character preceded by a backslash is equivalent to the +character itself. +.It Fl s +Concatenate all of the lines of each separate input file in command line +order. +The newline character of every line except the last line in each input +file is replaced with the tab character, unless otherwise specified by +the -d option. +.El +.Pp +If +.Ql Fl +is specified for one or more of the input files, the standard +input is used; standard input is read one line at a time, circularly, +for each instance of +.Ql Fl . +.Pp +The +.Nm paste +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr cut 1 +.Sh STANDARDS +The +.Nm paste +utility is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/paste/paste.c b/usr.bin/paste/paste.c new file mode 100644 index 0000000..7f17e1d --- /dev/null +++ b/usr.bin/paste/paste.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam S. Moskowitz of Menlo Consulting. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)paste.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +char *delim; +int delimcnt; + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + int ch, seq; + + seq = 0; + while ((ch = getopt(argc, argv, "d:s")) != EOF) + switch(ch) { + case 'd': + delimcnt = tr(delim = optarg); + break; + case 's': + seq = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!delim) { + delimcnt = 1; + delim = "\t"; + } + + if (seq) + sequential(argv); + else + parallel(argv); + exit(0); +} + +typedef struct _list { + struct _list *next; + FILE *fp; + int cnt; + char *name; +} LIST; + +parallel(argv) + char **argv; +{ + register LIST *lp; + register int cnt; + register char ch, *p; + LIST *head, *tmp; + int opencnt, output; + char buf[_POSIX2_LINE_MAX + 1], *malloc(); + + for (cnt = 0, head = NULL; p = *argv; ++argv, ++cnt) { + if (!(lp = (LIST *)malloc((u_int)sizeof(LIST)))) { + (void)fprintf(stderr, "paste: %s.\n", strerror(ENOMEM)); + exit(1); + } + if (p[0] == '-' && !p[1]) + lp->fp = stdin; + else if (!(lp->fp = fopen(p, "r"))) { + (void)fprintf(stderr, "paste: %s: %s.\n", p, + strerror(errno)); + exit(1); + } + lp->next = NULL; + lp->cnt = cnt; + lp->name = p; + if (!head) + head = tmp = lp; + else { + tmp->next = lp; + tmp = lp; + } + } + + for (opencnt = cnt; opencnt;) { + for (output = 0, lp = head; lp; lp = lp->next) { + if (!lp->fp) { + if (output && lp->cnt && + (ch = delim[(lp->cnt - 1) % delimcnt])) + putchar(ch); + continue; + } + if (!fgets(buf, sizeof(buf), lp->fp)) { + if (!--opencnt) + break; + lp->fp = NULL; + if (output && lp->cnt && + (ch = delim[(lp->cnt - 1) % delimcnt])) + putchar(ch); + continue; + } + if (!(p = index(buf, '\n'))) { + (void)fprintf(stderr, + "paste: %s: input line too long.\n", + lp->name); + exit(1); + } + *p = '\0'; + /* + * make sure that we don't print any delimiters + * unless there's a non-empty file. + */ + if (!output) { + output = 1; + for (cnt = 0; cnt < lp->cnt; ++cnt) + if (ch = delim[cnt % delimcnt]) + putchar(ch); + } else if (ch = delim[(lp->cnt - 1) % delimcnt]) + putchar(ch); + (void)printf("%s", buf); + } + if (output) + putchar('\n'); + } +} + +sequential(argv) + char **argv; +{ + register FILE *fp; + register int cnt; + register char ch, *p, *dp; + char buf[_POSIX2_LINE_MAX + 1]; + + for (; p = *argv; ++argv) { + if (p[0] == '-' && !p[1]) + fp = stdin; + else if (!(fp = fopen(p, "r"))) { + (void)fprintf(stderr, "paste: %s: %s.\n", p, + strerror(errno)); + continue; + } + if (fgets(buf, sizeof(buf), fp)) { + for (cnt = 0, dp = delim;;) { + if (!(p = index(buf, '\n'))) { + (void)fprintf(stderr, + "paste: %s: input line too long.\n", + *argv); + exit(1); + } + *p = '\0'; + (void)printf("%s", buf); + if (!fgets(buf, sizeof(buf), fp)) + break; + if (ch = *dp++) + putchar(ch); + if (++cnt == delimcnt) { + dp = delim; + cnt = 0; + } + } + putchar('\n'); + } + if (fp != stdin) + (void)fclose(fp); + } +} + +tr(arg) + char *arg; +{ + register int cnt; + register char ch, *p; + + for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt) + if (ch == '\\') + switch(ch = *p++) { + case 'n': + *arg = '\n'; + break; + case 't': + *arg = '\t'; + break; + case '0': + *arg = '\0'; + break; + default: + *arg = ch; + break; + } else + *arg = ch; + + if (!cnt) { + (void)fprintf(stderr, "paste: no delimiters specified.\n"); + exit(1); + } + return(cnt); +} + +usage() +{ + (void)fprintf(stderr, "paste: [-s] [-d delimiters] file ...\n"); + exit(1); +} diff --git a/usr.bin/patch/EXTERN.h b/usr.bin/patch/EXTERN.h new file mode 100644 index 0000000..0271074 --- /dev/null +++ b/usr.bin/patch/EXTERN.h @@ -0,0 +1,15 @@ +/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $ + * + * $Log: EXTERN.h,v $ + * Revision 2.0 86/09/17 15:35:37 lwall + * Baseline for netwide release. + * + */ + +#undef EXT +#define EXT extern + +#undef INIT +#define INIT(x) + +#undef DOINIT diff --git a/usr.bin/patch/INTERN.h b/usr.bin/patch/INTERN.h new file mode 100644 index 0000000..8bf16f5 --- /dev/null +++ b/usr.bin/patch/INTERN.h @@ -0,0 +1,15 @@ +/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $ + * + * $Log: INTERN.h,v $ + * Revision 2.0 86/09/17 15:35:58 lwall + * Baseline for netwide release. + * + */ + +#undef EXT +#define EXT + +#undef INIT +#define INIT(x) = x + +#define DOINIT diff --git a/usr.bin/patch/config.h b/usr.bin/patch/config.h new file mode 100644 index 0000000..9318fe7 --- /dev/null +++ b/usr.bin/patch/config.h @@ -0,0 +1,16 @@ +#define Reg1 register /**/ +#define Reg2 register /**/ +#define Reg3 register /**/ +#define Reg4 register /**/ +#define Reg5 register /**/ +#define Reg6 register /**/ +#define Reg7 register /**/ +#define Reg8 register /**/ +#define Reg9 register /**/ +#define Reg10 register /**/ +#define Reg11 /**/ +#define Reg12 /**/ +#define Reg13 /**/ +#define Reg14 /**/ +#define Reg15 /**/ +#define Reg16 /**/ diff --git a/usr.bin/patch/patchlevel.h b/usr.bin/patch/patchlevel.h new file mode 100644 index 0000000..618bca4 --- /dev/null +++ b/usr.bin/patch/patchlevel.h @@ -0,0 +1 @@ +#define PATCHLEVEL 9 diff --git a/usr.bin/patch/version.c b/usr.bin/patch/version.c new file mode 100644 index 0000000..17dfb81 --- /dev/null +++ b/usr.bin/patch/version.c @@ -0,0 +1,28 @@ +/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $ + * + * $Log: version.c,v $ + * Revision 2.0 86/09/17 15:40:11 lwall + * Baseline for netwide release. + * + */ + +#include "EXTERN.h" +#include "common.h" +#include "util.h" +#include "INTERN.h" +#include "patchlevel.h" +#include "version.h" + +/* Print out the version number and die. */ + +void +version() +{ + extern char rcsid[]; + +#ifdef lint + rcsid[0] = rcsid[0]; +#else + fatal3("%s\nPatch level: %d\n", rcsid, PATCHLEVEL); +#endif +} diff --git a/usr.bin/patch/version.h b/usr.bin/patch/version.h new file mode 100644 index 0000000..08fe68d --- /dev/null +++ b/usr.bin/patch/version.h @@ -0,0 +1,9 @@ +/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $ + * + * $Log: version.h,v $ + * Revision 2.0 86/09/17 15:40:14 lwall + * Baseline for netwide release. + * + */ + +void version(); diff --git a/usr.bin/pr/Makefile b/usr.bin/pr/Makefile new file mode 100644 index 0000000..70a921d --- /dev/null +++ b/usr.bin/pr/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= pr +SRCS= pr.c egetopt.c + +.include diff --git a/usr.bin/pr/egetopt.c b/usr.bin/pr/egetopt.c new file mode 100644 index 0000000..dd5bbbd --- /dev/null +++ b/usr.bin/pr/egetopt.c @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 1991 Keith Muller. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)egetopt.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include "extern.h" + +/* + * egetopt: get option letter from argument vector (an extended + * version of getopt). + * + * Non standard additions to the ostr specs are: + * 1) '?': immediate value following arg is optional (no white space + * between the arg and the value) + * 2) '#': +/- followed by a number (with an optional sign but + * no white space between the arg and the number). The - may be + * combined with other options, but the + cannot. + */ + +int eopterr = 1; /* if error message should be printed */ +int eoptind = 1; /* index into parent argv vector */ +int eoptopt; /* character checked for validity */ +char *eoptarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define EMSG "" + +int +egetopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + register char *oli; /* option letter list index */ + static int delim; /* which option delimeter */ + register char *p; + static char savec = '\0'; + + if (savec != '\0') { + *place = savec; + savec = '\0'; + } + + if (!*place) { + /* + * update scanning pointer + */ + if ((eoptind >= nargc) || + ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) { + place = EMSG; + return (EOF); + } + + delim = (int)*place; + if (place[1] && *++place == '-' && !place[1]) { + /* + * found "--" + */ + ++eoptind; + place = EMSG; + return (EOF); + } + } + + /* + * check option letter + */ + if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') || + !(oli = strchr(ostr, eoptopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF when by itself. + */ + if ((eoptopt == (int)'-') && !*place) + return (EOF); + if (strchr(ostr, '#') && (isdigit(eoptopt) || + (((eoptopt == (int)'-') || (eoptopt == (int)'+')) && + isdigit(*place)))) { + /* + * # option: +/- with a number is ok + */ + for (p = place; *p != '\0'; ++p) { + if (!isdigit(*p)) + break; + } + eoptarg = place-1; + + if (*p == '\0') { + place = EMSG; + ++eoptind; + } else { + place = p; + savec = *p; + *place = '\0'; + } + return (delim); + } + + if (!*place) + ++eoptind; + if (eopterr) { + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + (void)fprintf(stderr, "%s: illegal option -- %c\n", + p, eoptopt); + } + return (BADCH); + } + if (delim == (int)'+') { + /* + * '+' is only allowed with numbers + */ + if (!*place) + ++eoptind; + if (eopterr) { + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + (void)fprintf(stderr, + "%s: illegal '+' delimiter with option -- %c\n", + p, eoptopt); + } + return (BADCH); + } + ++oli; + if ((*oli != ':') && (*oli != '?')) { + /* + * don't need argument + */ + eoptarg = NULL; + if (!*place) + ++eoptind; + return (eoptopt); + } + + if (*place) { + /* + * no white space + */ + eoptarg = place; + } else if (*oli == '?') { + /* + * no arg, but NOT required + */ + eoptarg = NULL; + } else if (nargc <= ++eoptind) { + /* + * no arg, but IS required + */ + place = EMSG; + if (eopterr) { + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", p, + eoptopt); + } + return (BADCH); + } else { + /* + * arg has white space + */ + eoptarg = nargv[eoptind]; + } + place = EMSG; + ++eoptind; + return (eoptopt); +} diff --git a/usr.bin/pr/extern.h b/usr.bin/pr/extern.h new file mode 100644 index 0000000..1456b55 --- /dev/null +++ b/usr.bin/pr/extern.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1991 Keith Muller. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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.h 8.1 (Berkeley) 6/6/93 + */ + +extern int eoptind; +extern char *eoptarg; + +void addnum __P((char *, int, int)); +int egetopt __P((int, char * const *, const char *)); +void flsh_errs __P((void)); +int horzcol __P((int, char **)); +int inln __P((FILE *, char *, int, int *, int, int *)); +int inskip __P((FILE *, int, int)); +void mfail __P((void)); +int mulfile __P((int, char **)); +FILE *nxtfile __P((int, char **, char **, char *, int)); +int onecol __P((int, char **)); +int otln __P((char *, int, int *, int *, int)); +void pfail __P((void)); +int prhead __P((char *, char *, int)); +int prtail __P((int, int)); +int setup __P((int, char **)); +void terminate __P((int)); +void usage __P((void)); +int vertcol __P((int, char **)); diff --git a/usr.bin/pr/pr.1 b/usr.bin/pr/pr.1 new file mode 100644 index 0000000..d8d55be --- /dev/null +++ b/usr.bin/pr/pr.1 @@ -0,0 +1,347 @@ +.\" Copyright (c) 1991 Keith Muller. +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Keith Muller of the University of California, San Diego. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)pr.1 8.3 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt PR 1 +.Os BSD 4.4 +.Sh NAME +.Nm pr +.Nd print files +.Sh SYNOPSIS +.Nm pr +.Bk -words +.Op Ar \&+page +.Ek +.Bk -words +.Op Fl Ar column +.Ek +.Op Fl adFmrt +.Bk -words +.Oo +.Op Fl e +.Op Ar char +.Op Ar gap +.Oc +.Ek +.Bk -words +.Op Fl h Ar header +.Ek +.Bk -words +.Oo +.Op Fl i +.Op Ar char +.Op Ar gap +.Oc +.Ek +.Bk -words +.Op Fl l Ar lines +.Ek +.Bk -words +.Op Fl o Ar offset +.Ek +.Bk -words +.Oo +.Op Fl s +.Op Ar char +.Oc +.Ek +.Bk -words +.Oo +.Op Fl n +.Op Ar char +.Op Ar width +.Oc +.Ek +.Bk -words +.Op Fl w Ar width +.Ek +.Op - +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm pr +utility is a printing and pagination filter for text files. +When multiple input files are specified, each is read, formatted, +and written to standard output. +By default, the input is separated into 66-line pages, each with +.sp +.in +2 +.ti -2 +\(bu A 5-line header with the page number, date, time, and +the pathname of the file. +.sp +.ti -2 +\(bu A 5-line trailer consisting of blank lines. +.in -2 +.Pp +If standard output is associated with a terminal, +diagnostic messages are suppressed until the +.Nm pr +utility has completed processing. +.Pp +When multiple column output is specified, +text columns are of equal width. +By default text columns are separated by at least one +.Em . +Input lines that do not fit into a text column are truncated. +Lines are not truncated under single column output. +.Sh OPTIONS +.Pp +In the following option descriptions, column, lines, offset, page, and +width are positive decimal integers and gap is a nonnegative decimal integer. +.Bl -tag -width 4n +.It Ar \&+page +Begin output at page number +.Ar page +of the formatted input. +.It Fl Ar column +Produce output that is +.Ar columns +wide (default is 1) that is written vertically +down each column in the order in which the text +is received from the input file. +The options +.Fl e +and +.Fl i +are assumed. +This option should not be used with +.Fl m . +When used with +.Fl t , +the minimum number of lines is used to display the output. +.It Fl a +Modify the effect of the +.Fl column +option so that the columns are filled across the page in a round-robin order +(e.g., when column is 2, the first input line heads column +1, the second heads column 2, the third is the second line +in column 1, etc.). +This option requires the use of the +.Fl column +option. +.It Fl d +Produce output that is double spaced. An extra +.Em +character is output following every found in the input. +.It Fl e Ar \&[char\&]\&[gap\&] +Expand each input to the next greater column +position specified by the formula +.Ar n*gap+1 , +where +.Em n +is an integer > 0. +If +.Ar gap +is zero or is omitted the default is 8. +All +.Em +characters in the input are expanded into the appropriate +number of +.Em s . +If any nondigit character, +.Ar char , +is specified, it is used as the input tab character. +.It Fl F +Use a +.Em +character for new pages, +instead of the default behavior that uses a +sequence o +.Em +characters. +.It Fl h Ar header +.Ar header +Use the string +.Ar header +to replace the +.Ar file name +in the header line. +.It Fl i Ar \&[char\&]\&[gap\&] +In output, replace multiple s with s whenever two or more +adjacent s reach column positions +.Ar gap+1 , +.Ar 2*gap+1 , +etc. +If +.Ar gap +is zero or omitted, default +.Em +settings at every eighth column position +is used. +If any nondigit character, +.Ar char , +is specified, it is used as the output +.Em +character. +.It Fl l Ar lines +Override the 66 line default and reset the page length to +.Ar lines. +If +.Ar lines +is not greater than the sum of both the header and trailer +depths (in lines), the +.Nm pr +utility suppresses output of both the header and trailer, as if the +.Fl t +option were in effect. +.It Fl m +Merge the contents of multiple files. +One line from each file specified by a file operand is +written side by side into text columns of equal fixed widths, in +terms of the number of column positions. +The number of text columns depends on the number of +file operands successfully opened. +The maximum number of files merged depends on page width and the +per process open file limit. +The options +.Fl e +and +.Fl i +are assumed. +.It Fl n Ar \&[char\&]\&[width\&] +Provide +.Ar width +digit line numbering. +The default for +.Ar width , +if not specified, is 5. +The number occupies the first +.Ar width +column positions of each text column or each line of +.Fl m +output. +If +.Ar char +(any nondigit character) is given, it is appended to the line number to +separate it from whatever follows. The default for +.Ar char +is a +.Em . +Line numbers longer than +.Ar width +columns are truncated. +.It Fl o Ar offset +Each line of output is preceded by +.Ar offset +.Em s . +If the +.FL o +option is not specified, the default is zero. +The space taken is in addition to the output line width. +.It Fl r +Write no diagnostic reports on failure to open a file. +.It Fl s Ar char +Separate text columns by the single character +.Ar char +instead of by the appropriate number of +.Em s +(default for +.Ar char +is the +.Em +character). +.It Fl t +Print neither the five-line identifying +header nor the five-line trailer usually supplied for each page. +Quit printing after the last line of each file without spacing to the +end of the page. +.It Fl w Ar width +Set the width of the line to +.Ar width +column positions for multiple text-column output only. +If the +.Fl w +option is not specified and the +.Fl s +option is not specified, the default width is 72. +If the +.Fl w +option is not specified and the +.Fl s +option is specified, the default width is 512. +.It Ar file +A pathname of a file to be printed. +If no +.Ar file +operands are specified, or if a +.Ar file +operand is +.Sq Fl , +the standard input is used. +The standard input is used only if no +.Ar file +operands are specified, or if a +.Ar file +operand is +.Sq Fl . +.El +.Pp +The +.Fl s +option does not allow the option letter to be separated from its +argument, and the options +.Fl e , +.Fl i , +and +.Fl n +require that both arguments, if present, not be separated from the option +letter. +.Sh ERRORS +.Pp +If +.Nm pr +receives an interrupt while printing to a terminal, it +flushes all accumulated error messages to the screen before +terminating. +.Pp +The +.Nm pr +utility exits 0 on success, and 1 if an error occurs. +.Pp +Error messages are written to standard error during the printing +process (if output is redirected) or after all successful +file printing is complete (when printing to a terminal). +.Sh SEE ALSO +.Xr cat 1 , +.Xr more 1 +.Sh STANDARDS +The +.Nm pr +utility is +.St -p1003.2 +compatible. diff --git a/usr.bin/pr/pr.c b/usr.bin/pr/pr.c new file mode 100644 index 0000000..bbc7e9b --- /dev/null +++ b/usr.bin/pr/pr.c @@ -0,0 +1,1804 @@ +/*- + * Copyright (c) 1991 Keith Muller. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)pr.c 8.2 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pr.h" +#include "extern.h" + +/* + * pr: a printing and pagination filter. If multiple input files + * are specified, each is read, formatted, and written to standard + * output. By default, input is seperated into 66-line pages, each + * with a header that includes the page number, date, time and the + * files pathname. + * + * Complies with posix P1003.2/D11 + */ + +/* + * parameter variables + */ +int pgnm; /* starting page number */ +int clcnt; /* number of columns */ +int colwd; /* column data width - multiple columns */ +int across; /* mult col flag; write across page */ +int dspace; /* double space flag */ +char inchar; /* expand input char */ +int ingap; /* expand input gap */ +int formfeed; /* use formfeed as trailer */ +char *header; /* header name instead of file name */ +char ochar; /* contract output char */ +int ogap; /* contract output gap */ +int lines; /* number of lines per page */ +int merge; /* merge multiple files in output */ +char nmchar; /* line numbering append char */ +int nmwd; /* width of line number field */ +int offst; /* number of page offset spaces */ +int nodiag; /* do not report file open errors */ +char schar; /* text column separation character */ +int sflag; /* -s option for multiple columns */ +int nohead; /* do not write head and trailer */ +int pgwd; /* page width with multiple col output */ +char *timefrmt; /* time conversion string */ + +/* + * misc globals + */ +FILE *err; /* error message file pointer */ +int addone; /* page length is odd with double space */ +int errcnt; /* error count on file processing */ +char digs[] = "0123456789"; /* page number translation map */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ret_val; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void)signal(SIGINT, terminate); + ret_val = setup(argc, argv); + if (!ret_val) { + /* + * select the output format based on options + */ + if (merge) + ret_val = mulfile(argc, argv); + else if (clcnt == 1) + ret_val = onecol(argc, argv); + else if (across) + ret_val = horzcol(argc, argv); + else + ret_val = vertcol(argc, argv); + } else + usage(); + flsh_errs(); + if (errcnt || ret_val) + exit(1); + return(0); +} + +/* + * onecol: print files with only one column of output. + * Line length is unlimited. + */ +int +onecol(argc, argv) + int argc; + char *argv[]; +{ + register int cnt = -1; + register int off; + register int lrgln; + register int linecnt; + register int num; + int lncnt; + int pagecnt; + int ips; + int ops; + int cps; + char *obuf; + char *lbuf; + char *nbuf; + char *hbuf; + char *ohbuf; + FILE *inf; + char *fname; + int mor; + + if (nmwd) + num = nmwd + 1; + else + num = 0; + off = num + offst; + + /* + * allocate line buffer + */ + if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + /* + * allocate header buffer + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + + ohbuf = hbuf + offst; + nbuf = obuf + offst; + lbuf = nbuf + num; + if (num) + nbuf[--num] = nmchar; + if (offst) { + (void)memset(obuf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + if (pgnm) { + /* + * skip to specified page + */ + if (inskip(inf, pgnm, lines)) + continue; + pagecnt = pgnm; + } else + pagecnt = 1; + lncnt = 0; + + /* + * loop by page + */ + for(;;) { + linecnt = 0; + lrgln = 0; + ops = 0; + ips = 0; + cps = 0; + + /* + * loop by line + */ + while (linecnt < lines) { + /* + * input next line + */ + if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) + break; + if (!linecnt && !nohead && + prhead(hbuf, fname, pagecnt)) + return(1); + + /* + * start of new line. + */ + if (!lrgln) { + if (num) + addnum(nbuf, num, ++lncnt); + if (otln(obuf,cnt+off, &ips, &ops, mor)) + return(1); + } else if (otln(lbuf, cnt, &ips, &ops, mor)) + return(1); + + /* + * if line bigger than buffer, get more + */ + if (mor) { + lrgln = 1; + continue; + } + + /* + * whole line rcvd. reset tab proc. state + */ + ++linecnt; + lrgln = 0; + ops = 0; + ips = 0; + } + + /* + * fill to end of page + */ + if (linecnt && prtail(lines-linecnt-lrgln, lrgln)) + return(1); + + /* + * On EOF go to next file + */ + if (cnt < 0) + break; + ++pagecnt; + } + if (inf != stdin) + (void)fclose(inf); + } + if (eoptind < argc) + return(1); + return(0); +} + +/* + * vertcol: print files with more than one column of output down a page + */ +int +vertcol(argc, argv) + int argc; + char *argv[]; +{ + register char *ptbf; + register char **lstdat; + register int i; + register int j; + register int cnt = -1; + register int pln; + register int *indy; + int cvc; + int *lindy; + int lncnt; + int stp; + int pagecnt; + int col = colwd + 1; + int mxlen = pgwd + offst + 1; + int mclcnt = clcnt - 1; + struct vcol *vc; + int mvc; + int tvc; + int cw = nmwd + 1; + int fullcol; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + FILE *inf; + int ips = 0; + int cps = 0; + int ops = 0; + int mor = 0; + + /* + * allocate page buffer + */ + if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { + mfail(); + return(1); + } + + /* + * allocate page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + if (offst) + (void)memset(hbuf, (int)' ', offst); + + /* + * col pointers when no headers + */ + mvc = lines * clcnt; + if ((vc = + (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { + mfail(); + return(1); + } + + /* + * pointer into page where last data per line is located + */ + if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ + mfail(); + return(1); + } + + /* + * fast index lookups to locate start of lines + */ + if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { + mfail(); + return(1); + } + if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { + mfail(); + return(1); + } + + if (nmwd) + fullcol = col + cw; + else + fullcol = col; + + /* + * initialize buffer lookup indexes and offset area + */ + for (j = 0; j < lines; ++j) { + lindy[j] = j * mxlen; + indy[j] = lindy[j] + offst; + if (offst) { + ptbf = buf + lindy[j]; + (void)memset(ptbf, (int)' ', offst); + ptbf += offst; + } else + ptbf = buf + indy[j]; + lstdat[j] = ptbf; + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + if (pgnm) { + /* + * skip to requested page + */ + if (inskip(inf, pgnm, lines)) + continue; + pagecnt = pgnm; + } else + pagecnt = 1; + lncnt = 0; + + /* + * loop by page + */ + for(;;) { + /* + * loop by column + */ + cvc = 0; + for (i = 0; i < clcnt; ++i) { + j = 0; + /* + * if last column, do not pad + */ + if (i == mclcnt) + stp = 1; + else + stp = 0; + /* + * loop by line + */ + for(;;) { + /* + * is this first column + */ + if (!i) { + ptbf = buf + indy[j]; + lstdat[j] = ptbf; + } else + ptbf = lstdat[j]; + vc[cvc].pt = ptbf; + + /* + * add number + */ + if (nmwd) { + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } + + /* + * input next line + */ + cnt = inln(inf,ptbf,colwd,&cps,1,&mor); + vc[cvc++].cnt = cnt; + if (cnt < 0) + break; + ptbf += cnt; + + /* + * pad all but last column on page + */ + if (!stp) { + /* + * pad to end of column + */ + if (sflag) + *ptbf++ = schar; + else if ((pln = col-cnt) > 0) { + (void)memset(ptbf, + (int)' ',pln); + ptbf += pln; + } + } + /* + * remember last char in line + */ + lstdat[j] = ptbf; + if (++j >= lines) + break; + } + if (cnt < 0) + break; + } + + /* + * when -t (no header) is specified the spec requires + * the min number of lines. The last page may not have + * balanced length columns. To fix this we must reorder + * the columns. This is a very slow technique so it is + * only used under limited conditions. Without -t, the + * balancing of text columns is unspecified. To NOT + * balance the last page, add the global variable + * nohead to the if statement below e.g. + * + * if ((cnt < 0) && nohead && cvc ...... + */ + --cvc; + + /* + * check to see if last page needs to be reordered + */ + if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){ + pln = cvc/clcnt; + if (cvc % clcnt) + ++pln; + + /* + * print header + */ + if (!nohead && prhead(hbuf, fname, pagecnt)) + return(1); + for (i = 0; i < pln; ++i) { + ips = 0; + ops = 0; + if (offst&& otln(buf,offst,&ips,&ops,1)) + return(1); + tvc = i; + + for (j = 0; j < clcnt; ++j) { + /* + * determine column length + */ + if (j == mclcnt) { + /* + * last column + */ + cnt = vc[tvc].cnt; + if (nmwd) + cnt += cw; + } else if (sflag) { + /* + * single ch between + */ + cnt = vc[tvc].cnt + 1; + if (nmwd) + cnt += cw; + } else + cnt = fullcol; + if (otln(vc[tvc].pt, cnt, &ips, + &ops, 1)) + return(1); + tvc += pln; + if (tvc >= cvc) + break; + } + /* + * terminate line + */ + if (otln(buf, 0, &ips, &ops, 0)) + return(1); + } + /* + * pad to end of page + */ + if (prtail((lines - pln), 0)) + return(1); + /* + * done with output, go to next file + */ + break; + } + + /* + * determine how many lines to output + */ + if (i > 0) + pln = lines; + else + pln = j; + + /* + * print header + */ + if (pln && !nohead && prhead(hbuf, fname, pagecnt)) + return(1); + + /* + * output each line + */ + for (i = 0; i < pln; ++i) { + ptbf = buf + lindy[i]; + if ((j = lstdat[i] - ptbf) <= offst) + break; + if (otln(ptbf, j, &ips, &ops, 0)) + return(1); + } + + /* + * pad to end of page + */ + if (pln && prtail((lines - pln), 0)) + return(1); + + /* + * if EOF go to next file + */ + if (cnt < 0) + break; + ++pagecnt; + } + if (inf != stdin) + (void)fclose(inf); + } + if (eoptind < argc) + return(1); + return(0); +} + +/* + * horzcol: print files with more than one column of output across a page + */ +int +horzcol(argc, argv) + int argc; + char *argv[]; +{ + register char *ptbf; + register int pln; + register int cnt = -1; + register char *lstdat; + register int col = colwd + 1; + register int j; + register int i; + int lncnt; + int pagecnt; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + FILE *inf; + int ips = 0; + int cps = 0; + int ops = 0; + int mor = 0; + + if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + + /* + * page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + if (offst) { + (void)memset(buf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + if (pgnm) { + if (inskip(inf, pgnm, lines)) + continue; + pagecnt = pgnm; + } else + pagecnt = 1; + lncnt = 0; + + /* + * loop by page + */ + for(;;) { + /* + * loop by line + */ + for (i = 0; i < lines; ++i) { + ptbf = buf + offst; + lstdat = ptbf; + j = 0; + /* + * loop by col + */ + for(;;) { + if (nmwd) { + /* + * add number to column + */ + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } + /* + * input line + */ + if ((cnt = inln(inf,ptbf,colwd,&cps,1, + &mor)) < 0) + break; + ptbf += cnt; + lstdat = ptbf; + + /* + * if last line skip padding + */ + if (++j >= clcnt) + break; + + /* + * pad to end of column + */ + if (sflag) + *ptbf++ = schar; + else if ((pln = col - cnt) > 0) { + (void)memset(ptbf,(int)' ',pln); + ptbf += pln; + } + } + + /* + * determine line length + */ + if ((j = lstdat - buf) <= offst) + break; + if (!i && !nohead && + prhead(hbuf, fname, pagecnt)) + return(1); + /* + * output line + */ + if (otln(buf, j, &ips, &ops, 0)) + return(1); + } + + /* + * pad to end of page + */ + if (i && prtail(lines-i, 0)) + return(1); + + /* + * if EOF go to next file + */ + if (cnt < 0) + break; + ++pagecnt; + } + if (inf != stdin) + (void)fclose(inf); + } + if (eoptind < argc) + return(1); + return(0); +} + +/* + * mulfile: print files with more than one column of output and + * more than one file concurrently + */ +int +mulfile(argc, argv) + int argc; + char *argv[]; +{ + register char *ptbf; + register int j; + register int pln; + register int cnt; + register char *lstdat; + register int i; + FILE **fbuf; + int actf; + int lncnt; + int col; + int pagecnt; + int fproc; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + int ips = 0; + int cps = 0; + int ops = 0; + int mor = 0; + + /* + * array of FILE *, one for each operand + */ + if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { + mfail(); + return(1); + } + + /* + * page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + + /* + * do not know how many columns yet. The number of operands provide an + * upper bound on the number of columns. We use the number of files + * we can open successfully to set the number of columns. The operation + * of the merge operation (-m) in relation to unsuccesful file opens + * is unspecified by posix. + */ + j = 0; + while (j < clcnt) { + if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) + break; + if (pgnm && (inskip(fbuf[j], pgnm, lines))) + fbuf[j] = NULL; + ++j; + } + + /* + * if no files, exit + */ + if (!j) + return(1); + + /* + * calculate page boundries based on open file count + */ + clcnt = j; + if (nmwd) { + colwd = (pgwd - clcnt - nmwd)/clcnt; + pgwd = ((colwd + 1) * clcnt) - nmwd - 2; + } else { + colwd = (pgwd + 1 - clcnt)/clcnt; + pgwd = ((colwd + 1) * clcnt) - 1; + } + if (colwd < 1) { + (void)fprintf(err, + "pr: page width too small for %d columns\n", clcnt); + return(1); + } + actf = clcnt; + col = colwd + 1; + + /* + * line buffer + */ + if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + if (offst) { + (void)memset(buf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + if (pgnm) + pagecnt = pgnm; + else + pagecnt = 1; + lncnt = 0; + + /* + * continue to loop while any file still has data + */ + while (actf > 0) { + /* + * loop by line + */ + for (i = 0; i < lines; ++i) { + ptbf = buf + offst; + lstdat = ptbf; + if (nmwd) { + /* + * add line number to line + */ + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } + j = 0; + fproc = 0; + + /* + * loop by column + */ + for (j = 0; j < clcnt; ++j) { + if (fbuf[j] == NULL) { + /* + * empty column; EOF + */ + cnt = 0; + } else if ((cnt = inln(fbuf[j], ptbf, colwd, + &cps, 1, &mor)) < 0) { + /* + * EOF hit; no data + */ + if (fbuf[j] != stdin) + (void)fclose(fbuf[j]); + fbuf[j] = NULL; + --actf; + cnt = 0; + } else { + /* + * process file data + */ + ptbf += cnt; + lstdat = ptbf; + fproc++; + } + + /* + * if last ACTIVE column, done with line + */ + if (fproc >= actf) + break; + + /* + * pad to end of column + */ + if (sflag) { + *ptbf++ = schar; + } else if ((pln = col - cnt) > 0) { + (void)memset(ptbf, (int)' ', pln); + ptbf += pln; + } + } + + /* + * calculate data in line + */ + if ((j = lstdat - buf) <= offst) + break; + + if (!i && !nohead && prhead(hbuf, fname, pagecnt)) + return(1); + + /* + * output line + */ + if (otln(buf, j, &ips, &ops, 0)) + return(1); + + /* + * if no more active files, done + */ + if (actf <= 0) { + ++i; + break; + } + } + + /* + * pad to end of page + */ + if (i && prtail(lines-i, 0)) + return(1); + ++pagecnt; + } + if (eoptind < argc) + return(1); + return(0); +} + +/* + * inln(): input a line of data (unlimited length lines supported) + * Input is optionally expanded to spaces + * + * inf: file + * buf: buffer + * lim: buffer length + * cps: column positon 1st char in buffer (large line support) + * trnc: throw away data more than lim up to \n + * mor: set if more data in line (not truncated) + */ +int +inln(inf, buf, lim, cps, trnc, mor) + FILE *inf; + char *buf; + register int lim; + int *cps; + int trnc; + int *mor; +{ + register int col; + register int gap = ingap; + register int ch = EOF; + register char *ptbuf; + register int chk = (int)inchar; + + ptbuf = buf; + + if (gap) { + /* + * expanding input option + */ + while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { + /* + * is this the input "tab" char + */ + if (ch == chk) { + /* + * expand to number of spaces + */ + col = (ptbuf - buf) + *cps; + col = gap - (col % gap); + + /* + * if more than this line, push back + */ + if ((col > lim) && (ungetc(ch, inf) == EOF)) + return(1); + + /* + * expand to spaces + */ + while ((--col >= 0) && (--lim >= 0)) + *ptbuf++ = ' '; + continue; + } + if (ch == '\n') + break; + *ptbuf++ = ch; + } + } else { + /* + * no expansion + */ + while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { + if (ch == '\n') + break; + *ptbuf++ = ch; + } + } + col = ptbuf - buf; + if (ch == EOF) { + *mor = 0; + *cps = 0; + if (!col) + return(-1); + return(col); + } + if (ch == '\n') { + /* + * entire line processed + */ + *mor = 0; + *cps = 0; + return(col); + } + + /* + * line was larger than limit + */ + if (trnc) { + /* + * throw away rest of line + */ + while ((ch = getc(inf)) != EOF) { + if (ch == '\n') + break; + } + *cps = 0; + *mor = 0; + } else { + /* + * save column offset if not truncated + */ + *cps += col; + *mor = 1; + } + + return(col); +} + +/* + * otln(): output a line of data. (Supports unlimited length lines) + * output is optionally contracted to tabs + * + * buf: output buffer with data + * cnt: number of chars of valid data in buf + * svips: buffer input column position (for large lines) + * svops: buffer output column position (for large lines) + * mor: output line not complete in this buf; more data to come. + * 1 is more, 0 is complete, -1 is no \n's + */ +int +otln(buf, cnt, svips, svops, mor) + register char *buf; + int cnt; + int *svops; + int *svips; + int mor; +{ + register int ops; /* last col output */ + register int ips; /* last col in buf examined */ + register int gap = ogap; + register int tbps; + register char *endbuf; + + if (ogap) { + /* + * contracting on output + */ + endbuf = buf + cnt; + ops = *svops; + ips = *svips; + while (buf < endbuf) { + /* + * count number of spaces and ochar in buffer + */ + if (*buf == ' ') { + ++ips; + ++buf; + continue; + } + + /* + * simulate ochar processing + */ + if (*buf == ochar) { + ips += gap - (ips % gap); + ++buf; + continue; + } + + /* + * got a non space char; contract out spaces + */ + while (ops < ips) { + /* + * use as many ochar as will fit + */ + if ((tbps = ops + gap - (ops % gap)) > ips) + break; + if (putchar(ochar) == EOF) { + pfail(); + return(1); + } + ops = tbps; + } + + while (ops < ips) { + /* + * finish off with spaces + */ + if (putchar(' ') == EOF) { + pfail(); + return(1); + } + ++ops; + } + + /* + * output non space char + */ + if (putchar(*buf++) == EOF) { + pfail(); + return(1); + } + ++ips; + ++ops; + } + + if (mor > 0) { + /* + * if incomplete line, save position counts + */ + *svops = ops; + *svips = ips; + return(0); + } + + if (mor < 0) { + while (ops < ips) { + /* + * use as many ochar as will fit + */ + if ((tbps = ops + gap - (ops % gap)) > ips) + break; + if (putchar(ochar) == EOF) { + pfail(); + return(1); + } + ops = tbps; + } + while (ops < ips) { + /* + * finish off with spaces + */ + if (putchar(' ') == EOF) { + pfail(); + return(1); + } + ++ops; + } + return(0); + } + } else { + /* + * output is not contracted + */ + if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { + pfail(); + return(1); + } + if (mor != 0) + return(0); + } + + /* + * process line end and double space as required + */ + if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { + pfail(); + return(1); + } + return(0); +} + +/* + * inskip(): skip over pgcnt pages with lncnt lines per page + * file is closed at EOF (if not stdin). + * + * inf FILE * to read from + * pgcnt number of pages to skip + * lncnt number of lines per page + */ +int +inskip(inf, pgcnt, lncnt) + FILE *inf; + register int pgcnt; + register int lncnt; +{ + register int c; + register int cnt; + + while(--pgcnt > 0) { + cnt = lncnt; + while ((c = getc(inf)) != EOF) { + if ((c == '\n') && (--cnt == 0)) + break; + } + if (c == EOF) { + if (inf != stdin) + (void)fclose(inf); + return(1); + } + } + return(0); +} + +/* + * nxtfile: returns a FILE * to next file in arg list and sets the + * time field for this file (or current date). + * + * buf array to store proper date for the header. + * dt if set skips the date processing (used with -m) + */ +FILE * +nxtfile(argc, argv, fname, buf, dt) + int argc; + char **argv; + char **fname; + char *buf; + int dt; +{ + FILE *inf = NULL; + struct timeval tv; + struct timezone tz; + struct tm *timeptr = NULL; + struct stat statbuf; + static int twice = -1; + + ++twice; + if (eoptind >= argc) { + /* + * no file listed; default, use standard input + */ + if (twice) + return(NULL); + clearerr(stdin); + inf = stdin; + if (header != NULL) + *fname = header; + else + *fname = FNAME; + if (nohead) + return(inf); + if (gettimeofday(&tv, &tz) < 0) { + ++errcnt; + (void)fprintf(err, "pr: cannot get time of day, %s\n", + strerror(errno)); + eoptind = argc - 1; + return(NULL); + } + timeptr = localtime(&(tv.tv_sec)); + } + for (; eoptind < argc; ++eoptind) { + if (strcmp(argv[eoptind], "-") == 0) { + /* + * process a "-" for filename + */ + clearerr(stdin); + inf = stdin; + if (header != NULL) + *fname = header; + else + *fname = FNAME; + ++eoptind; + if (nohead || (dt && twice)) + return(inf); + if (gettimeofday(&tv, &tz) < 0) { + ++errcnt; + (void)fprintf(err, + "pr: cannot get time of day, %s\n", + strerror(errno)); + return(NULL); + } + timeptr = localtime(&(tv.tv_sec)); + } else { + /* + * normal file processing + */ + if ((inf = fopen(argv[eoptind], "r")) == NULL) { + ++errcnt; + if (nodiag) + continue; + (void)fprintf(err, "pr: Cannot open %s, %s\n", + argv[eoptind], strerror(errno)); + continue; + } + if (header != NULL) + *fname = header; + else if (dt) + *fname = FNAME; + else + *fname = argv[eoptind]; + ++eoptind; + if (nohead || (dt && twice)) + return(inf); + + if (dt) { + if (gettimeofday(&tv, &tz) < 0) { + ++errcnt; + (void)fprintf(err, + "pr: cannot get time of day, %s\n", + strerror(errno)); + return(NULL); + } + timeptr = localtime(&(tv.tv_sec)); + } else { + if (fstat(fileno(inf), &statbuf) < 0) { + ++errcnt; + (void)fclose(inf); + (void)fprintf(err, + "pr: Cannot stat %s, %s\n", + argv[eoptind], strerror(errno)); + return(NULL); + } + timeptr = localtime(&(statbuf.st_mtime)); + } + } + break; + } + if (inf == NULL) + return(NULL); + + /* + * set up time field used in header + */ + if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { + ++errcnt; + if (inf != stdin) + (void)fclose(inf); + (void)fputs("pr: time conversion failed\n", err); + return(NULL); + } + return(inf); +} + +/* + * addnum(): adds the line number to the column + * Truncates from the front or pads with spaces as required. + * Numbers are right justified. + * + * buf buffer to store the number + * wdth width of buffer to fill + * line line number + * + * NOTE: numbers occupy part of the column. The posix + * spec does not specify if -i processing should or should not + * occur on number padding. The spec does say it occupies + * part of the column. The usage of addnum currently treats + * numbers as part of the column so spaces may be replaced. + */ +void +addnum(buf, wdth, line) + register char *buf; + register int wdth; + register int line; +{ + register char *pt = buf + wdth; + + do { + *--pt = digs[line % 10]; + line /= 10; + } while (line && (pt > buf)); + + /* + * pad with space as required + */ + while (pt > buf) + *--pt = ' '; +} + +/* + * prhead(): prints the top of page header + * + * buf buffer with time field (and offset) + * cnt number of chars in buf + * fname fname field for header + * pagcnt page number + */ +int +prhead(buf, fname, pagcnt) + char *buf; + char *fname; + int pagcnt; +{ + int ips = 0; + int ops = 0; + + if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { + pfail(); + return(1); + } + /* + * posix is not clear if the header is subject to line length + * restrictions. The specification for header line format + * in the spec clearly does not limit length. No pr currently + * restricts header length. However if we need to truncate in + * an reasonable way, adjust the length of the printf by + * changing HDFMT to allow a length max as an arguement printf. + * buf (which contains the offset spaces and time field could + * also be trimmed + * + * note only the offset (if any) is processed for tab expansion + */ + if (offst && otln(buf, offst, &ips, &ops, -1)) + return(1); + (void)printf(HDFMT,buf+offst, fname, pagcnt); + return(0); +} + +/* + * prtail(): pad page with empty lines (if required) and print page trailer + * if requested + * + * cnt number of lines of padding needed + * incomp was a '\n' missing from last line output + */ +int +prtail(cnt, incomp) + register int cnt; + int incomp; +{ + if (nohead) { + /* + * only pad with no headers when incomplete last line + */ + if (!incomp) + return(0); + if ((dspace && (putchar('\n') == EOF)) || + (putchar('\n') == EOF)) { + pfail(); + return(1); + } + return(0); + } + + /* + * if double space output two \n + */ + if (dspace) + cnt *= 2; + + /* + * if an odd number of lines per page, add an extra \n + */ + if (addone) + ++cnt; + + /* + * pad page + */ + if (formfeed) { + if ((incomp && (putchar('\n') == EOF)) || + (putchar('\f') == EOF)) { + pfail(); + return(1); + } + return(0); + } + cnt += TAILLEN; + while (--cnt >= 0) { + if (putchar('\n') == EOF) { + pfail(); + return(1); + } + } + return(0); +} + +/* + * terminate(): when a SIGINT is recvd + */ +void +terminate(which_sig) + int which_sig; +{ + flsh_errs(); + exit(1); +} + + +/* + * flsh_errs(): output saved up diagnostic messages after all normal + * processing has completed + */ +void +flsh_errs() +{ + char buf[BUFSIZ]; + + (void)fflush(stdout); + (void)fflush(err); + if (err == stderr) + return; + rewind(err); + while (fgets(buf, BUFSIZ, err) != NULL) + (void)fputs(buf, stderr); +} + +void +mfail() +{ + (void)fputs("pr: memory allocation failed\n", err); +} + +void +pfail() +{ + (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); +} + +void +usage() +{ + (void)fputs( + "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err); + (void)fputs( + " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); + (void)fputs( + " [-s[ch]] [-w width] [-] [file ...]\n", err); +} + +/* + * setup: Validate command args, initialize and perform sanity + * checks on options + */ +int +setup(argc, argv) + register int argc; + register char **argv; +{ + register int c; + int eflag = 0; + int iflag = 0; + int wflag = 0; + int cflag = 0; + + if (isatty(fileno(stdout))) { + /* + * defer diagnostics until processing is done + */ + if ((err = tmpfile()) == NULL) { + (void)fputs("Cannot defer diagnostic messages\n",stderr); + return(1); + } + } else + err = stderr; + while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != EOF) { + switch (c) { + case '+': + if ((pgnm = atoi(eoptarg)) < 1) { + (void)fputs("pr: +page number must be 1 or more\n", + err); + return(1); + } + break; + case '-': + if ((clcnt = atoi(eoptarg)) < 1) { + (void)fputs("pr: -columns must be 1 or more\n",err); + return(1); + } + if (clcnt > 1) + ++cflag; + break; + case 'a': + ++across; + break; + case 'd': + ++dspace; + break; + case 'e': + ++eflag; + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + inchar = *eoptarg++; + else + inchar = INCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((ingap = atoi(eoptarg)) < 0) { + (void)fputs( + "pr: -e gap must be 0 or more\n", err); + return(1); + } + if (ingap == 0) + ingap = INGAP; + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -e %s\n", eoptarg); + return(1); + } else + ingap = INGAP; + break; + case 'F': + ++formfeed; + break; + case 'h': + header = eoptarg; + break; + case 'i': + ++iflag; + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + ochar = *eoptarg++; + else + ochar = OCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((ogap = atoi(eoptarg)) < 0) { + (void)fputs( + "pr: -i gap must be 0 or more\n", err); + return(1); + } + if (ogap == 0) + ogap = OGAP; + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -i %s\n", eoptarg); + return(1); + } else + ogap = OGAP; + break; + case 'l': + if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) { + (void)fputs( + "pr: Number of lines must be 1 or more\n",err); + return(1); + } + break; + case 'm': + ++merge; + break; + case 'n': + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + nmchar = *eoptarg++; + else + nmchar = NMCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((nmwd = atoi(eoptarg)) < 1) { + (void)fputs( + "pr: -n width must be 1 or more\n",err); + return(1); + } + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -n %s\n", eoptarg); + return(1); + } else + nmwd = NMWD; + break; + case 'o': + if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){ + (void)fputs("pr: -o offset must be 1 or more\n", + err); + return(1); + } + break; + case 'r': + ++nodiag; + break; + case 's': + ++sflag; + if (eoptarg == NULL) + schar = SCHAR; + else + schar = *eoptarg++; + if (*eoptarg != '\0') { + (void)fprintf(err, + "pr: invalid value for -s %s\n", eoptarg); + return(1); + } + break; + case 't': + ++nohead; + break; + case 'w': + ++wflag; + if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){ + (void)fputs( + "pr: -w width must be 1 or more \n",err); + return(1); + } + break; + case '?': + default: + return(1); + } + } + + /* + * default and sanity checks + */ + if (!clcnt) { + if (merge) { + if ((clcnt = argc - eoptind) <= 1) { + clcnt = CLCNT; + merge = 0; + } + } else + clcnt = CLCNT; + } + if (across) { + if (clcnt == 1) { + (void)fputs("pr: -a flag requires multiple columns\n", + err); + return(1); + } + if (merge) { + (void)fputs("pr: -m cannot be used with -a\n", err); + return(1); + } + } + if (!wflag) { + if (sflag) + pgwd = SPGWD; + else + pgwd = PGWD; + } + if (cflag || merge) { + if (!eflag) { + inchar = INCHAR; + ingap = INGAP; + } + if (!iflag) { + ochar = OCHAR; + ogap = OGAP; + } + } + if (cflag) { + if (merge) { + (void)fputs( + "pr: -m cannot be used with multiple columns\n", err); + return(1); + } + if (nmwd) { + colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; + pgwd = ((colwd + nmwd + 2) * clcnt) - 1; + } else { + colwd = (pgwd + 1 - clcnt)/clcnt; + pgwd = ((colwd + 1) * clcnt) - 1; + } + if (colwd < 1) { + (void)fprintf(err, + "pr: page width is too small for %d columns\n",clcnt); + return(1); + } + } + if (!lines) + lines = LINES; + + /* + * make sure long enough for headers. if not disable + */ + if (lines <= HEADLEN + TAILLEN) + ++nohead; + else if (!nohead) + lines -= HEADLEN + TAILLEN; + + /* + * adjust for double space on odd length pages + */ + if (dspace) { + if (lines == 1) + dspace = 0; + else { + if (lines & 1) + ++addone; + lines /= 2; + } + } + + if ((timefrmt = getenv("LC_TIME")) == NULL) + timefrmt = TIMEFMT; + return(0); +} diff --git a/usr.bin/pr/pr.h b/usr.bin/pr/pr.h new file mode 100644 index 0000000..d020e9f --- /dev/null +++ b/usr.bin/pr/pr.h @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 1991 Keith Muller. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pr.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * parameter defaults + */ +#define CLCNT 1 +#define INCHAR '\t' +#define INGAP 8 +#define OCHAR '\t' +#define OGAP 8 +#define LINES 66 +#define NMWD 5 +#define NMCHAR '\t' +#define SCHAR '\t' +#define PGWD 72 +#define SPGWD 512 + +/* + * misc default values + */ +#define HDFMT "%s %s Page %d\n\n\n" +#define HEADLEN 5 +#define TAILLEN 5 +#define TIMEFMT "%b %e %H:%M %Y" +#define FNAME "" +#define LBUF 8192 +#define HDBUF 512 + +/* + * structure for vertical columns. Used to balance cols on last page + */ +struct vcol { + char *pt; /* ptr to col */ + int cnt; /* char count */ +}; diff --git a/usr.bin/printenv/Makefile b/usr.bin/printenv/Makefile new file mode 100644 index 0000000..94975bd --- /dev/null +++ b/usr.bin/printenv/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= printenv +MLINKS= printenv.1 env.1 + +.include diff --git a/usr.bin/printenv/printenv.1 b/usr.bin/printenv/printenv.1 new file mode 100644 index 0000000..77d78f8 --- /dev/null +++ b/usr.bin/printenv/printenv.1 @@ -0,0 +1,98 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)printenv.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PRINTENV 1 +.Os BSD 3 +.Sh NAME +.Nm printenv , env +.Nd print out the environment, set and print environment +.Sh SYNOPSIS +.Nm printenv +.Op Ar name +.Nm env +.Op Fl +.Op Ar name=value ... +.Op Ar command +.Sh DESCRIPTION +.Nm Printenv +prints out the names and values of the variables in the environment, +with one name/value pair per line. If +.Ar name +is specified, only +its value is printed. +.Pp +If a +.Ar name +is specified and it is not defined in the environment, +.Nm printenv +returns exit status 1, else it returns status 0. +.Pp +.Nm Env +executes +.Ar command +after modifying the environment as +specified on the command line. The option +.Ar name=value +specifies +an environmental variable, +.Ar name , +with a value of +.Ar value . +The option +.Sq Fl +causes +.Nm env +to completely ignore the environment +it inherits. +.Pp +If no command is specified, +.Nm env +prints out the names and values +of the variables in the environment, with one name/value pair per line. +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr execvp 3 , +.Xr environ 7 +.Sh HISTORY +The +.Nm printenv +command appeared in +.Bx 3.0 . +.Sh BUGS +.Nm Env +doesn't handle commands with equal (``='') signs in their +names, for obvious reasons. diff --git a/usr.bin/printenv/printenv.c b/usr.bin/printenv/printenv.c new file mode 100644 index 0000000..121cd2f --- /dev/null +++ b/usr.bin/printenv/printenv.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)printenv.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include + +void usage __P((void)); + +/* + * printenv + * + * Bill Joy, UCB + * February, 1979 + */ +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char **environ; + register char *cp, **ep; + register size_t len; + int ch; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc == 0) { + for (ep = environ; *ep; ep++) + (void)printf("%s\n", *ep); + exit(0); + } + len = strlen(*argv); + for (ep = environ; *ep; ep++) + if (!memcmp(*ep, *argv, len)) { + cp = *ep + len; + if (!*cp || *cp == '=') { + (void)printf("%s\n", *cp ? cp + 1 : cp); + exit(0); + } + } + exit(1); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: printenv [name]\n"); + exit(1); +} diff --git a/usr.bin/printf/Makefile b/usr.bin/printf/Makefile new file mode 100644 index 0000000..52b20f4 --- /dev/null +++ b/usr.bin/printf/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= printf + +.include diff --git a/usr.bin/printf/printf.1 b/usr.bin/printf/printf.1 new file mode 100644 index 0000000..4954158 --- /dev/null +++ b/usr.bin/printf/printf.1 @@ -0,0 +1,272 @@ +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)printf.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt PRINTF 1 +.Os +.Sh NAME +.Nm printf +.Nd formatted output +.Sh SYNOPSIS +.Nm printf format +.Op arguments ... +.Sh DESCRIPTION +.Nm Printf +formats and prints its arguments, after the first, under control +of the +.Ar format . +The +.Ar format +is a character string which contains three types of objects: plain characters, +which are simply copied to standard output, character escape sequences which +are converted and copied to the standard output, and format specifications, +each of which causes printing of the next successive +.Ar argument . +.Pp +The +.Ar arguments +after the first are treated as strings if the corresponding format is +either +.Cm c +or +.Cm s ; +otherwise it is evaluated as a C constant, with the following extensions: +.Pp +.Bl -bullet -offset indent -compact +.It +A leading plus or minus sign is allowed. +.It +If the leading character is a single or double quote, or not a digit, +plus, or minus sign, the value is the ASCII code of the next character. +.El +.Pp +The format string is reused as often as necessary to satisfy the +.Ar arguments . +Any extra format specifications are evaluated with zero or the null +string. +.Pp +Character escape sequences are in backslash notation as defined in the +draft proposed +.Tn ANSI C +Standard +.Tn X3J11 . +The characters and their meanings +are as follows: +.Bl -tag -width Ds -offset indent +.It Cm \ea +Write a character. +.It Cm \eb +Write a character. +.It Cm \ef +Write a character. +.It Cm \en +Write a character. +.It Cm \er +Write a character. +.It Cm \et +Write a character. +.It Cm \ev +Write a character. +.It Cm \e\' +Write a character. +.It Cm \e\e +Write a backslash character. +.It Cm \e Ns Ar num +Write an 8-bit character whose +.Tn ASCII +value is the 1-, 2-, or 3-digit +octal number +.Ar num . +.El +.Pp +Each format specification is introduced by the percent character +(``%''). +The remainder of the format specification includes, +in the following order: +.Bl -tag -width Ds +.It "Zero or more of the following flags:" +.Bl -tag -width Ds +.It Cm # +A `#' character +specifying that the value should be printed in an ``alternate form''. +For +.Cm c , +.Cm d , +and +.Cm s , +formats, this option has no effect. For the +.Cm o +formats the precision of the number is increased to force the first +character of the output string to a zero. For the +.Cm x +.Pq Cm X +format, a non-zero result has the string +.Li 0x +.Pq Li 0X +prepended to it. For +.Cm e , +.Cm E , +.Cm f , +.Cm g , +and +.Cm G , +formats, the result will always contain a decimal point, even if no +digits follow the point (normally, a decimal point only appears in the +results of those formats if a digit follows the decimal point). For +.Cm g +and +.Cm G +formats, trailing zeros are not removed from the result as they +would otherwise be; +.It Cm \&\- +A minus sign `\-' which specifies +.Em left adjustment +of the output in the indicated field; +.It Cm \&+ +A `+' character specifying that there should always be +a sign placed before the number when using signed formats. +.It Sq \&\ \& +A space specifying that a blank should be left before a positive number +for a signed format. A `+' overrides a space if both are used; +.It Cm \&0 +A zero `0' character indicating that zero-padding should be used +rather than blank-padding. A `\-' overrides a `0' if both are used; +.El +.It "Field Width:" +An optional digit string specifying a +.Em field width ; +if the output string has fewer characters than the field width it will +be blank-padded on the left (or right, if the left-adjustment indicator +has been given) to make up the field width (note that a leading zero +is a flag, but an embedded zero is part of a field width); +.It Precision: +An optional period, +.Sq Cm \&.\& , +followed by an optional digit string giving a +.Em precision +which specifies the number of digits to appear after the decimal point, +for +.Cm e +and +.Cm f +formats, or the maximum number of characters to be printed +from a string; if the digit string is missing, the precision is treated +as zero; +.It Format: +A character which indicates the type of format to use (one of +.Cm diouxXfwEgGcs ) . +.El +.Pp +A field width or precision may be +.Sq Cm \&* +instead of a digit string. +In this case an +.Ar argument +supplies the field width or precision. +.Pp +The format characters and their meanings are: +.Bl -tag -width Fl +.It Cm diouXx +The +.Ar argument +is printed as a signed decimal (d or i), unsigned decimal, unsigned octal, +or unsigned hexadecimal (X or x), respectively. +.It Cm f +The +.Ar argument +is printed in the style `[\-]ddd.ddd' where the number of d's +after the decimal point is equal to the precision specification for +the argument. +If the precision is missing, 6 digits are given; if the precision +is explicitly 0, no digits and no decimal point are printed. +.It Cm eE +The +.Ar argument +is printed in the style +.Cm e +.`[-]d.ddd Ns \(+-dd\' +where there +is one digit before the decimal point and the number after is equal to +the precision specification for the argument; when the precision is +missing, 6 digits are produced. +An upper-case E is used for an `E' format. +.It Cm gG +The +.Ar argument +is printed in style +.Cm f +or in style +.Cm e +.Pq Cm E +whichever gives full precision in minimum space. +.It Cm c +The first character of +.Ar argument +is printed. +.It Cm s +Characters from the string +.Ar argument +are printed until the end is reached or until the number of characters +indicated by the precision specification is reached; however if the +precision is 0 or missing, all characters in the string are printed. +.It Cm \&% +Print a `%'; no argument is used. +.El +.Pp +In no case does a non-existent or small field width cause truncation of +a field; padding takes place only if the specified field width exceeds +the actual width. +.Sh RETURN VALUES +.Nm Printf +exits 0 on success, 1 on failure. +.Sh SEE ALSO +.Xr printf 3 +.Sh HISTORY +The +.Nm printf +command appeared in +.Bx 4.3 Reno . +It is modeled +after the standard library function, +.Xr printf 3 . +.Sh BUGS +Since the floating point numbers are translated from +.Tn ASCII +to floating-point and +then back again, floating-point precision may be lost. +.Pp +.Tn ANSI +hexadecimal character constants were deliberately not provided. diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c new file mode 100644 index 0000000..69f0c8e --- /dev/null +++ b/usr.bin/printf/printf.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 1989, 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. + */ + +#if !defined(BUILTIN) && !defined(SHELL) +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ +#endif + +#ifndef lint +static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#ifdef SHELL +#define EOF -1 +#else +#include +#endif +#include +#include + +/* + * XXX + * This *has* to go away. TK. + */ +#ifdef SHELL +#define main printfcmd +#define warnx(a, b, c) { \ + char buf[64]; \ + (void)sprintf(buf, sizeof(buf), a, b, c); \ + error(buf); \ +} +#include "../../bin/sh/bltin/bltin.h" +#endif + +#define PF(f, func) { \ + if (fieldwidth) \ + if (precision) \ + (void)printf(f, fieldwidth, precision, func); \ + else \ + (void)printf(f, fieldwidth, func); \ + else if (precision) \ + (void)printf(f, precision, func); \ + else \ + (void)printf(f, func); \ +} + +static int asciicode __P((void)); +static void escape __P((char *)); +static int getchr __P((void)); +static double getdouble __P((void)); +static int getint __P((int *)); +static int getlong __P((long *)); +static char *getstr __P((void)); +static char *mklong __P((char *, int)); +static void usage __P((void)); + +static char **gargv; + +int +#ifdef BUILTIN +progprintf(argc, argv) +#else +main(argc, argv) +#endif + int argc; + char *argv[]; +{ + extern int optind; + static char *skip1, *skip2; + int ch, end, fieldwidth, precision; + char convch, nextch, *format, *fmt, *start; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + usage(); + return (1); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + return (1); + } + + /* + * Basic algorithm is to scan the format string for conversion + * specifications -- once one is found, find out if the field + * width or precision is a '*'; if it is, gather up value. Note, + * format strings are reused as necessary to use up the provided + * arguments, arguments of zero/null string are provided to use + * up the format string. + */ + skip1 = "#-+ 0"; + skip2 = "*0123456789"; + + escape(fmt = format = *argv); /* backslash interpretation */ + gargv = ++argv; + for (;;) { + end = 0; + /* find next format specification */ +next: for (start = fmt;; ++fmt) { + if (!*fmt) { + /* avoid infinite loop */ + if (end == 1) { + warnx("missing format character", + NULL, NULL); + return (1); + } + end = 1; + if (fmt > start) + (void)printf("%s", start); + if (!*gargv) + return (0); + fmt = format; + goto next; + } + /* %% prints a % */ + if (*fmt == '%') { + if (*++fmt != '%') + break; + *fmt++ = '\0'; + (void)printf("%s", start); + goto next; + } + } + + /* skip to field width */ + for (; strchr(skip1, *fmt); ++fmt); + if (*fmt == '*') { + if (getint(&fieldwidth)) + return (1); + } else + fieldwidth = 0; + + /* skip to possible '.', get following precision */ + for (; strchr(skip2, *fmt); ++fmt); + if (*fmt == '.') + ++fmt; + if (*fmt == '*') { + if (getint(&precision)) + return (1); + } else + precision = 0; + + /* skip to conversion char */ + for (; strchr(skip2, *fmt); ++fmt); + if (!*fmt) { + warnx("missing format character", NULL, NULL); + return (1); + } + + convch = *fmt; + nextch = *++fmt; + *fmt = '\0'; + switch(convch) { + case 'c': { + char p; + + p = getchr(); + PF(start, p); + break; + } + case 's': { + char *p; + + p = getstr(); + PF(start, p); + break; + } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + long p; + char *f; + + if ((f = mklong(start, convch)) == NULL) + return (1); + if (getlong(&p)) + return (1); + PF(f, p); + break; + } + case 'e': case 'E': case 'f': case 'g': case 'G': { + double p; + + p = getdouble(); + PF(start, p); + break; + } + default: + warnx("illegal format character", NULL, NULL); + return (1); + } + *fmt = nextch; + } + /* NOTREACHED */ +} + +static char * +mklong(str, ch) + char *str; + int ch; +{ + static char copy[64]; + int len; + + len = strlen(str) + 2; + memmove(copy, str, len - 3); + copy[len - 3] = 'l'; + copy[len - 2] = ch; + copy[len - 1] = '\0'; + return (copy); +} + +static void +escape(fmt) + register char *fmt; +{ + register char *store; + register int value, c; + + for (store = fmt; c = *fmt; ++fmt, ++store) { + if (c != '\\') { + *store = c; + continue; + } + switch (*++fmt) { + case '\0': /* EOS, user error */ + *store = '\\'; + *++store = '\0'; + return; + case '\\': /* backslash */ + case '\'': /* single quote */ + *store = *fmt; + break; + case 'a': /* bell/alert */ + *store = '\7'; + break; + case 'b': /* backspace */ + *store = '\b'; + break; + case 'f': /* form-feed */ + *store = '\f'; + break; + case 'n': /* newline */ + *store = '\n'; + break; + case 'r': /* carriage-return */ + *store = '\r'; + break; + case 't': /* horizontal tab */ + *store = '\t'; + break; + case 'v': /* vertical tab */ + *store = '\13'; + break; + /* octal constant */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (c = 3, value = 0; + c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { + value <<= 3; + value += *fmt - '0'; + } + --fmt; + *store = value; + break; + default: + *store = *fmt; + break; + } + } + *store = '\0'; +} + +static int +getchr() +{ + if (!*gargv) + return ('\0'); + return ((int)**gargv++); +} + +static char * +getstr() +{ + if (!*gargv) + return (""); + return (*gargv++); +} + +static char *Number = "+-.0123456789"; +static int +getint(ip) + int *ip; +{ + long val; + + if (getlong(&val)) + return (1); + if (val > INT_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + *ip = val; + return (0); +} + +static int +getlong(lp) + long *lp; +{ + long val; + char *ep; + + if (!*gargv) { + *lp = 0; + return (0); + } + if (strchr(Number, **gargv)) { + errno = 0; + val = strtol(*gargv, &ep, 0); + if (*ep != '\0') { + warnx("%s: illegal number", *gargv, NULL); + return (1); + } + if (errno == ERANGE) + if (val == LONG_MAX) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + if (val == LONG_MIN) { + warnx("%s: %s", *gargv, strerror(ERANGE)); + return (1); + } + + *lp = val; + ++gargv; + return (0); + } + *lp = (long)asciicode(); + return (0); +} + +static double +getdouble() +{ + if (!*gargv) + return ((double)0); + if (strchr(Number, **gargv)) + return (atof(*gargv++)); + return ((double)asciicode()); +} + +static int +asciicode() +{ + register int ch; + + ch = **gargv; + if (ch == '\'' || ch == '"') + ch = (*gargv)[1]; + ++gargv; + return (ch); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: printf format [arg ...]\n"); +} diff --git a/usr.bin/quota/Makefile b/usr.bin/quota/Makefile new file mode 100644 index 0000000..2ee365e --- /dev/null +++ b/usr.bin/quota/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= quota +BINOWN= root +BINMODE=4555 + +.include diff --git a/usr.bin/quota/quota.1 b/usr.bin/quota/quota.1 new file mode 100644 index 0000000..e87a3a4 --- /dev/null +++ b/usr.bin/quota/quota.1 @@ -0,0 +1,131 @@ +.\" Copyright (c) 1983, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Elz at The University of Melbourne. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)quota.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt QUOTA 1 +.Os BSD 4.2 +.Sh NAME +.Nm quota +.Nd display disk usage and limits +.Sh SYNOPSIS +.Nm quota +.Op Fl g +.Op Fl u +.Op Fl v | Fl q +.Nm quota +.Op Fl u +.Op Fl v | Fl q +.Ar user +.Nm quota +.Op Fl g +.Op Fl v | Fl q +.Ar group +.Sh DESCRIPTION +.Nm Quota +displays users' disk usage and limits. +By default only the user quotas are printed. +.Pp +Options: +.Pp +.Bl -tag -width Ds +.It Fl g +Print group quotas for the group +of which the user is a member. +The optional +.Fl u +flag is equivalent to the default. +.It Fl v +.Nm quota +will display quotas on filesystems +where no storage is allocated. +.It Fl q +Print a more terse message, +containing only information +on filesystems where usage is over quota. +.El +.Pp +Specifying both +.Fl g +and +.Fl u +displays both the user quotas and the group quotas (for +the user). +.Pp +Only the super-user may use the +.Fl u +flag and the optional +.Ar user +argument to view the limits of other users. +Non-super-users can use the the +.Fl g +flag and optional +.Ar group +argument to view only the limits of groups of which they are members. +.Pp +The +.Fl q +flag takes precedence over the +.Fl v +flag. +.Pp +.Nm Quota +reports the quotas of all the filesystems listed in +.Pa /etc/fstab . +If +.Nm quota +exits with a non-zero status, one or more filesystems +are over quota. +.Sh FILES +.Bl -tag -width quota.group -compact +.It Pa quota.user +located at the filesystem root with user quotas +.It Pa quota.group +located at the filesystem root with group quotas +.It Pa /etc/fstab +to find filesystem names and locations +.El +.Sh HISTORY +The +.Nm quota +command appeared in +.Bx 4.2 . +.Sh SEE ALSO +.Xr quotactl 2 , +.Xr fstab 5 , +.Xr edquota 8 , +.Xr quotacheck 8 , +.Xr quotaon 8 , +.Xr repquota 8 diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c new file mode 100644 index 0000000..1d18a13 --- /dev/null +++ b/usr.bin/quota/quota.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 1980, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1980, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)quota.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Disk quota reporting program. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *qfname = QUOTAFILENAME; +char *qfextension[] = INITQFNAMES; + +struct quotause { + struct quotause *next; + long flags; + struct dqblk dqblk; + char fsname[MAXPATHLEN + 1]; +} *getprivs(); +#define FOUND 0x01 + +int qflag; +int vflag; + +main(argc, argv) + char *argv[]; +{ + int ngroups, gidset[NGROUPS]; + int i, gflag = 0, uflag = 0; + char ch; + extern char *optarg; + extern int optind, errno; + + if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == EOPNOTSUPP) { + fprintf(stderr, "There are no quotas on this system\n"); + exit(0); + } + while ((ch = getopt(argc, argv, "ugvq")) != EOF) { + switch(ch) { + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + case 'q': + qflag++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (!uflag && !gflag) + uflag++; + if (argc == 0) { + if (uflag) + showuid(getuid()); + if (gflag) { + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + exit(1); + } + for (i = 1; i < ngroups; i++) + showgid(gidset[i]); + } + exit(0); + } + if (uflag && gflag) + usage(); + if (uflag) { + for (; argc > 0; argc--, argv++) { + if (alldigits(*argv)) + showuid(atoi(*argv)); + else + showusrname(*argv); + } + exit(0); + } + if (gflag) { + for (; argc > 0; argc--, argv++) { + if (alldigits(*argv)) + showgid(atoi(*argv)); + else + showgrpname(*argv); + } + exit(0); + } +} + +usage() +{ + + fprintf(stderr, "%s\n%s\n%s\n", + "Usage: quota [-guqv]", + "\tquota [-qv] -u username ...", + "\tquota [-qv] -g groupname ..."); + exit(1); +} + +/* + * Print out quotas for a specified user identifier. + */ +showuid(uid) + u_long uid; +{ + struct passwd *pwd = getpwuid(uid); + u_long myuid; + char *name; + + if (pwd == NULL) + name = "(no account)"; + else + name = pwd->pw_name; + myuid = getuid(); + if (uid != myuid && myuid != 0) { + printf("quota: %s (uid %d): permission denied\n", name, uid); + return; + } + showquotas(USRQUOTA, uid, name); +} + +/* + * Print out quotas for a specifed user name. + */ +showusrname(name) + char *name; +{ + struct passwd *pwd = getpwnam(name); + u_long myuid; + + if (pwd == NULL) { + fprintf(stderr, "quota: %s: unknown user\n", name); + return; + } + myuid = getuid(); + if (pwd->pw_uid != myuid && myuid != 0) { + fprintf(stderr, "quota: %s (uid %d): permission denied\n", + name, pwd->pw_uid); + return; + } + showquotas(USRQUOTA, pwd->pw_uid, name); +} + +/* + * Print out quotas for a specified group identifier. + */ +showgid(gid) + u_long gid; +{ + struct group *grp = getgrgid(gid); + int ngroups, gidset[NGROUPS]; + register int i; + char *name; + + if (grp == NULL) + name = "(no entry)"; + else + name = grp->gr_name; + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + return; + } + for (i = 1; i < ngroups; i++) + if (gid == gidset[i]) + break; + if (i >= ngroups && getuid() != 0) { + fprintf(stderr, "quota: %s (gid %d): permission denied\n", + name, gid); + return; + } + showquotas(GRPQUOTA, gid, name); +} + +/* + * Print out quotas for a specifed group name. + */ +showgrpname(name) + char *name; +{ + struct group *grp = getgrnam(name); + int ngroups, gidset[NGROUPS]; + register int i; + + if (grp == NULL) { + fprintf(stderr, "quota: %s: unknown group\n", name); + return; + } + ngroups = getgroups(NGROUPS, gidset); + if (ngroups < 0) { + perror("quota: getgroups"); + return; + } + for (i = 1; i < ngroups; i++) + if (grp->gr_gid == gidset[i]) + break; + if (i >= ngroups && getuid() != 0) { + fprintf(stderr, "quota: %s (gid %d): permission denied\n", + name, grp->gr_gid); + return; + } + showquotas(GRPQUOTA, grp->gr_gid, name); +} + +showquotas(type, id, name) + int type; + u_long id; + char *name; +{ + register struct quotause *qup; + struct quotause *quplist, *getprivs(); + char *msgi, *msgb, *timeprt(); + int myuid, fd, lines = 0; + static int first; + static time_t now; + + if (now == 0) + time(&now); + quplist = getprivs(id, type); + for (qup = quplist; qup; qup = qup->next) { + if (!vflag && + qup->dqblk.dqb_isoftlimit == 0 && + qup->dqblk.dqb_ihardlimit == 0 && + qup->dqblk.dqb_bsoftlimit == 0 && + qup->dqblk.dqb_bhardlimit == 0) + continue; + msgi = (char *)0; + if (qup->dqblk.dqb_ihardlimit && + qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) + msgi = "File limit reached on"; + else if (qup->dqblk.dqb_isoftlimit && + qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) + if (qup->dqblk.dqb_itime > now) + msgi = "In file grace period on"; + else + msgi = "Over file quota on"; + msgb = (char *)0; + if (qup->dqblk.dqb_bhardlimit && + qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) + msgb = "Block limit reached on"; + else if (qup->dqblk.dqb_bsoftlimit && + qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) + if (qup->dqblk.dqb_btime > now) + msgb = "In block grace period on"; + else + msgb = "Over block quota on"; + if (qflag) { + if ((msgi != (char *)0 || msgb != (char *)0) && + lines++ == 0) + heading(type, id, name, ""); + if (msgi != (char *)0) + printf("\t%s %s\n", msgi, qup->fsname); + if (msgb != (char *)0) + printf("\t%s %s\n", msgb, qup->fsname); + continue; + } + if (vflag || + qup->dqblk.dqb_curblocks || + qup->dqblk.dqb_curinodes) { + if (lines++ == 0) + heading(type, id, name, ""); + printf("%15s%8d%c%7d%8d%8s" + , qup->fsname + , dbtob(qup->dqblk.dqb_curblocks) / 1024 + , (msgb == (char *)0) ? ' ' : '*' + , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024 + , dbtob(qup->dqblk.dqb_bhardlimit) / 1024 + , (msgb == (char *)0) ? "" + : timeprt(qup->dqblk.dqb_btime)); + printf("%8d%c%7d%8d%8s\n" + , qup->dqblk.dqb_curinodes + , (msgi == (char *)0) ? ' ' : '*' + , qup->dqblk.dqb_isoftlimit + , qup->dqblk.dqb_ihardlimit + , (msgi == (char *)0) ? "" + : timeprt(qup->dqblk.dqb_itime) + ); + continue; + } + } + if (!qflag && lines == 0) + heading(type, id, name, "none"); +} + +heading(type, id, name, tag) + int type; + u_long id; + char *name, *tag; +{ + + printf("Disk quotas for %s %s (%cid %d): %s\n", qfextension[type], + name, *qfextension[type], id, tag); + if (!qflag && tag[0] == '\0') { + printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n" + , "Filesystem" + , "blocks" + , "quota" + , "limit" + , "grace" + , "files" + , "quota" + , "limit" + , "grace" + ); + } +} + +/* + * Calculate the grace period and return a printable string for it. + */ +char * +timeprt(seconds) + time_t seconds; +{ + time_t hours, minutes; + static char buf[20]; + static time_t now; + + if (now == 0) + time(&now); + if (now > seconds) + return ("none"); + seconds -= now; + minutes = (seconds + 30) / 60; + hours = (minutes + 30) / 60; + if (hours >= 36) { + sprintf(buf, "%ddays", (hours + 12) / 24); + return (buf); + } + if (minutes >= 60) { + sprintf(buf, "%2d:%d", minutes / 60, minutes % 60); + return (buf); + } + sprintf(buf, "%2d", minutes); + return (buf); +} + +/* + * Collect the requested quota information. + */ +struct quotause * +getprivs(id, quotatype) + register long id; + int quotatype; +{ + register struct fstab *fs; + register struct quotause *qup, *quptail; + struct quotause *quphead; + char *qfpathname; + int qcmd, fd; + + setfsent(); + quphead = (struct quotause *)0; + qcmd = QCMD(Q_GETQUOTA, quotatype); + while (fs = getfsent()) { + if (strcmp(fs->fs_vfstype, "ufs")) + continue; + if (!hasquota(fs, quotatype, &qfpathname)) + continue; + if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) { + fprintf(stderr, "quota: out of memory\n"); + exit(2); + } + if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) { + if ((fd = open(qfpathname, O_RDONLY)) < 0) { + perror(qfpathname); + free(qup); + continue; + } + lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); + switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { + case 0: /* EOF */ + /* + * Convert implicit 0 quota (EOF) + * into an explicit one (zero'ed dqblk) + */ + bzero((caddr_t)&qup->dqblk, + sizeof(struct dqblk)); + break; + + case sizeof(struct dqblk): /* OK */ + break; + + default: /* ERROR */ + fprintf(stderr, "quota: read error"); + perror(qfpathname); + close(fd); + free(qup); + continue; + } + close(fd); + } + strcpy(qup->fsname, fs->fs_file); + if (quphead == NULL) + quphead = qup; + else + quptail->next = qup; + quptail = qup; + qup->next = 0; + } + endfsent(); + return (quphead); +} + +/* + * Check to see if a particular quota is to be enabled. + */ +hasquota(fs, type, qfnamep) + register struct fstab *fs; + int type; + char **qfnamep; +{ + register char *opt; + char *cp, *index(), *strtok(); + static char initname, usrname[100], grpname[100]; + static char buf[BUFSIZ]; + + if (!initname) { + sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); + sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); + initname = 1; + } + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if (cp = index(opt, '=')) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; + } + if (!opt) + return (0); + if (cp) { + *qfnamep = cp; + return (1); + } + (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); + *qfnamep = buf; + return (1); +} + +alldigits(s) + register char *s; +{ + register c; + + c = *s++; + do { + if (!isdigit(c)) + return (0); + } while (c = *s++); + return (1); +} diff --git a/usr.bin/ranlib/Makefile b/usr.bin/ranlib/Makefile new file mode 100644 index 0000000..4acf99e --- /dev/null +++ b/usr.bin/ranlib/Makefile @@ -0,0 +1,16 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ranlib +SRCS= archive.c build.c misc.c ranlib.c touch.c +CFLAGS+=-I${.CURDIR} -I${.CURDIR}/../ar +MAN1= ranlib.0 +VPATH= ${.CURDIR}/../ar +CLEANFILES=ranlib.5.0 + +ranlib.0: ranlib.5.0 + +afterinstall: + install -c -o ${MANOWN} -g ${MANGRP} -m ${MANMODE} ranlib.5.0 \ + ${DESTDIR}${MANDIR}5/ranlib.0 + +.include diff --git a/usr.bin/ranlib/build.c b/usr.bin/ranlib/build.c new file mode 100644 index 0000000..12a6dc6 --- /dev/null +++ b/usr.bin/ranlib/build.c @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)build.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "archive.h" + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ +extern char *tname; /* temporary file "name" */ + +typedef struct _rlib { + struct _rlib *next; /* next structure */ + off_t pos; /* offset of defining archive file */ + char *sym; /* symbol */ + int symlen; /* strlen(sym) */ +} RLIB; +RLIB *rhead, **pnext; + +FILE *fp; + +long symcnt; /* symbol count */ +long tsymlen; /* total string length */ + +static void rexec __P((int, int)); +static void symobj __P((void)); + +build() +{ + CF cf; + int afd, tfd; + off_t size; + + afd = open_archive(O_RDWR); + fp = fdopen(afd, "r+"); + tfd = tmp(); + + SETCF(afd, archive, tfd, tname, RPAD|WPAD); + + /* Read through the archive, creating list of symbols. */ + pnext = &rhead; + symcnt = tsymlen = 0; + while(get_arobj(afd)) { + if (!strcmp(chdr.name, RANLIBMAG)) { + skip_arobj(afd); + continue; + } + rexec(afd, tfd); + put_arobj(&cf, (struct stat *)NULL); + } + *pnext = NULL; + + /* Create the symbol table. */ + symobj(); + + /* Copy the saved objects into the archive. */ + size = lseek(tfd, (off_t)0, SEEK_CUR); + (void)lseek(tfd, (off_t)0, SEEK_SET); + SETCF(tfd, tname, afd, archive, RPAD|WPAD); + copy_ar(&cf, size); + (void)ftruncate(afd, lseek(afd, (off_t)0, SEEK_CUR)); + (void)close(tfd); + + /* Set the time. */ + settime(afd); + close_archive(afd); + return(0); +} + +/* + * rexec + * Read the exec structure; ignore any files that don't look + * exactly right. + */ +static void +rexec(rfd, wfd) + register int rfd; + int wfd; +{ + register RLIB *rp; + register long nsyms; + register int nr, symlen; + register char *strtab, *sym; + struct exec ebuf; + struct nlist nl; + off_t r_off, w_off; + long strsize; + void *emalloc(); + + /* Get current offsets for original and tmp files. */ + r_off = lseek(rfd, (off_t)0, SEEK_CUR); + w_off = lseek(wfd, (off_t)0, SEEK_CUR); + + /* Read in exec structure. */ + nr = read(rfd, &ebuf, sizeof(struct exec)); + if (nr != sizeof(struct exec)) + goto badread; + + /* Check magic number and symbol count. */ + if (N_BADMAG(ebuf) || ebuf.a_syms == 0) + goto bad1; + + /* Seek to string table. */ + if (lseek(rfd, r_off + N_STROFF(ebuf), SEEK_SET) == (off_t)-1) + error(archive); + + /* Read in size of the string table. */ + nr = read(rfd, &strsize, sizeof(strsize)); + if (nr != sizeof(strsize)) + goto badread; + + /* Read in the string table. */ + strsize -= sizeof(strsize); + strtab = emalloc(strsize); + nr = read(rfd, strtab, strsize); + if (nr != strsize) { +badread: if (nr < 0) + error(archive); + goto bad2; + } + + /* Seek to symbol table. */ + if (fseek(fp, (long)r_off + N_SYMOFF(ebuf), SEEK_SET)) + goto bad2; + + /* For each symbol read the nlist entry and save it as necessary. */ + nsyms = ebuf.a_syms / sizeof(struct nlist); + while (nsyms--) { + if (!fread(&nl, sizeof(struct nlist), 1, fp)) { + if (feof(fp)) + badfmt(); + error(archive); + } + + /* Ignore if no name or local. */ + if (!nl.n_un.n_strx || !(nl.n_type & N_EXT)) + continue; + + /* + * If the symbol is an undefined external and the n_value + * field is non-zero, keep it. + */ + if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value) + continue; + + /* First four bytes are the table size. */ + sym = strtab + nl.n_un.n_strx - sizeof(long); + symlen = strlen(sym) + 1; + + rp = (RLIB *)emalloc(sizeof(RLIB)); + rp->sym = (char *)emalloc(symlen); + bcopy(sym, rp->sym, symlen); + rp->symlen = symlen; + rp->pos = w_off; + + /* Build in forward order for "ar -m" command. */ + *pnext = rp; + pnext = &rp->next; + + ++symcnt; + tsymlen += symlen; + } + +bad2: free(strtab); +bad1: (void)lseek(rfd, r_off, SEEK_SET); +} + +/* + * symobj -- + * Write the symbol table into the archive, computing offsets as + * writing. + */ +static void +symobj() +{ + register RLIB *rp; + struct ranlib rn; + off_t ransize; + long size, stroff; + char hb[sizeof(struct ar_hdr) + 1], pad; + + /* Rewind the archive, leaving the magic number. */ + if (fseek(fp, (long)SARMAG, SEEK_SET)) + error(archive); + + /* Size of the ranlib archive file, pad if necessary. */ + ransize = sizeof(long) + + symcnt * sizeof(struct ranlib) + sizeof(long) + tsymlen; + if (ransize & 01) { + ++ransize; + pad = '\n'; + } else + pad = '\0'; + + /* Put out the ranlib archive file header. */ +#define DEFMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) + (void)sprintf(hb, HDR2, RANLIBMAG, 0L, getuid(), getgid(), + DEFMODE & ~umask(0), ransize, ARFMAG); + if (!fwrite(hb, sizeof(struct ar_hdr), 1, fp)) + error(tname); + + /* First long is the size of the ranlib structure section. */ + size = symcnt * sizeof(struct ranlib); + if (!fwrite(&size, sizeof(size), 1, fp)) + error(tname); + + /* Offset of the first archive file. */ + size = SARMAG + sizeof(struct ar_hdr) + ransize; + + /* + * Write out the ranlib structures. The offset into the string + * table is cumulative, the offset into the archive is the value + * set in rexec() plus the offset to the first archive file. + */ + for (rp = rhead, stroff = 0; rp; rp = rp->next) { + rn.ran_un.ran_strx = stroff; + stroff += rp->symlen; + rn.ran_off = size + rp->pos; + if (!fwrite(&rn, sizeof(struct ranlib), 1, fp)) + error(archive); + } + + /* Second long is the size of the string table. */ + if (!fwrite(&tsymlen, sizeof(tsymlen), 1, fp)) + error(tname); + + /* Write out the string table. */ + for (rp = rhead; rp; rp = rp->next) + if (!fwrite(rp->sym, rp->symlen, 1, fp)) + error(tname); + + if (pad && !fwrite(&pad, sizeof(pad), 1, fp)) + error(tname); + + (void)fflush(fp); +} diff --git a/usr.bin/ranlib/misc.c b/usr.bin/ranlib/misc.c new file mode 100644 index 0000000..d1c8076 --- /dev/null +++ b/usr.bin/ranlib/misc.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +extern char *archive; /* archive name */ +char *tname = "temporary file"; /* temporary file "name" */ + +tmp() +{ + sigset_t set, oset; + int fd; + char *envtmp, path[MAXPATHLEN]; + + if ((envtmp = getenv("TMPDIR")) != NULL) + (void)sprintf(path, "%s%s", envtmp, strrchr(_PATH_RANTMP, '/')); + else + bcopy(_PATH_RANTMP, path, sizeof(_PATH_RANTMP)); + + sigfillset(&set); + (void)sigprocmask(SIG_BLOCK, &set, &oset); + if ((fd = mkstemp(path)) == -1) + error(path); + (void)unlink(path); + (void)sigprocmask(SIG_SETMASK, &oset, NULL); + return(fd); +} + +void * +emalloc(len) + int len; +{ + void *p; + + if ((p = malloc((u_int)len)) == NULL) + error(archive); + return(p); +} + +char * +rname(path) + char *path; +{ + register char *ind; + + return((ind = rindex(path, '/')) ? ind + 1 : path); +} + +badfmt() +{ + errno = EFTYPE; + error(archive); +} + +error(name) + char *name; +{ + (void)fprintf(stderr, "ranlib: %s: %s\n", name, strerror(errno)); + exit(1); +} diff --git a/usr.bin/ranlib/pathnames.h b/usr.bin/ranlib/pathnames.h new file mode 100644 index 0000000..c1df3f9 --- /dev/null +++ b/usr.bin/ranlib/pathnames.h @@ -0,0 +1,36 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_RANTMP "/tmp/ranlib.XXXXXX" diff --git a/usr.bin/ranlib/ranlib.1 b/usr.bin/ranlib/ranlib.1 new file mode 100644 index 0000000..bd95cd2 --- /dev/null +++ b/usr.bin/ranlib/ranlib.1 @@ -0,0 +1,87 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ranlib.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt RANLIB 1 +.Os +.Sh NAME +.Nm ranlib +.Nd table-of-contents for archive libraries +.Sh SYNOPSIS +.Nm ranlib +.Op Fl t +.Ar file ... +.Sh DESCRIPTION +.Nm Ranlib +creates a table of external references for archive libraries, +normally used by the loader, +.Xr ld 1 . +This table is is named ``__.SYMDEF'' and is prepended to the archive. +Files in the archive which are not executable and symbols which are +uninteresting to the loader are ignored. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl t +Set the modification time of the __.SYMDEF file. +This time is compared by the loader with the modification time of the +archive to verify that the table is up-to-date with respect to the +archive. +If the modification time has been changed without any change to the +archive (for example, by a +.Xr cp 1 ) , +the +.Fl t +option can be used to ``touch'' the modification time so that it +appears that the table is up-to-date. +This is also useful after using the +.Fl t +option of +.Xr make 1 . +.El +.Sh FILES +.Bl -tag -width /tmp/ranlib.XXXXXX -compact +.It Pa /tmp/ranlib.XXXXXX +Temporary file names. +.El +.Sh SEE ALSO +.Xr ar 1 , +.Xr ld 1 , +.Xr lorder 1 , +.Xr nm 1 , +.Xr ranlib 5 +.Sh HISTORY +A +.Nm ranlib +command appeared in +.At v7 . diff --git a/usr.bin/ranlib/ranlib.5.5 b/usr.bin/ranlib/ranlib.5.5 new file mode 100644 index 0000000..e953c51 --- /dev/null +++ b/usr.bin/ranlib/ranlib.5.5 @@ -0,0 +1,70 @@ +.\" 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. +.\" +.\" @(#)ranlib.5.5 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt RANLIB 5 +.Os +.Sh NAME +.Nm ranlib +.Nd archive (library) table-of-contents format +.Sh SYNOPSIS +.Fd #include +.Sh DESCRIPTION +The archive table-of-contents command +.Nm ranlib +creates a table of contents for archives, containing object files, to +be used by the link-editor +.Xr ld 1 . +It operates on archives created with the utility +.Xr ar 1 . +.Pp +The +.Nm Ranlib +function +prepends a new file to the archive which has three separate parts. +The first part is a standard archive header, which has a special name +field, "__.SYMDEF". +.Pp +The second part is a ``long'' followed by a list of ranlib structures. +The long is the size, in bytes, of the list of ranlib structures. +Each of the ranlib structures consists of a zero based offset into the +next section (a string table of symbols) and an offset from the beginning +of the archive to the start of the archive file which defines the symbol. +The actual number of ranlib structures is this number divided by the size +of an individual ranlib structure. +.Pp +The third part is a ``long'' followed by a string table. +The long is the size, in bytes of the string table. +.Sh SEE ALSO +.Xr ar 1 , +.Xr ranlib 1 diff --git a/usr.bin/ranlib/ranlib.c b/usr.bin/ranlib/ranlib.c new file mode 100644 index 0000000..9d1d8a1 --- /dev/null +++ b/usr.bin/ranlib/ranlib.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ranlib.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +CHDR chdr; +u_int options; /* UNUSED -- keep open_archive happy */ +char *archive; + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + int ch, eval, tflag; + + tflag = 0; + while ((ch = getopt(argc, argv, "t")) != EOF) + switch(ch) { + case 't': + tflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!*argv) + usage(); + + for (eval = 0; archive = *argv++;) + eval |= tflag ? touch() : build(); + exit(eval); +} + +usage() +{ + (void)fprintf(stderr, "usage: ranlib [-t] archive ...\n"); + exit(1); +} diff --git a/usr.bin/ranlib/touch.c b/usr.bin/ranlib/touch.c new file mode 100644 index 0000000..4cf4b12 --- /dev/null +++ b/usr.bin/ranlib/touch.c @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern CHDR chdr; /* converted header */ +extern char *archive; /* archive name */ + +touch() +{ + int afd; + + afd = open_archive(O_RDWR); + + if (!get_arobj(afd) || + strncmp(RANLIBMAG, chdr.name, sizeof(RANLIBMAG) - 1)) { + (void)fprintf(stderr, + "ranlib: %s: no symbol table.\n", archive); + return(1); + } + settime(afd); + return(0); +} + +settime(afd) + int afd; +{ + struct ar_hdr *hdr; + off_t size; + char buf[50]; + + size = SARMAG + sizeof(hdr->ar_name); + if (lseek(afd, size, SEEK_SET) == (off_t)-1) + error(archive); + (void)sprintf(buf, "%-12ld", time((time_t *)NULL) + RANLIBSKEW); + if (write(afd, buf, sizeof(hdr->ar_date)) != sizeof(hdr->ar_date)) + error(archive); +} diff --git a/usr.bin/rdist/Makefile b/usr.bin/rdist/Makefile new file mode 100644 index 0000000..4b60c6b --- /dev/null +++ b/usr.bin/rdist/Makefile @@ -0,0 +1,14 @@ +# @(#)Makefile 8.3 (Berkeley) 7/19/93 + +PROG= rdist +CFLAGS+=-I${.CURDIR} +SRCS= docmd.c expand.c lookup.c main.c server.c +OBJS+= gram.o +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg +DPADD= ${LIBCOMPAT} +LDADD= -lcompat +CLEANFILES=y.tab.h + +.include diff --git a/usr.bin/rdist/cron.entry b/usr.bin/rdist/cron.entry new file mode 100644 index 0000000..90968cf --- /dev/null +++ b/usr.bin/rdist/cron.entry @@ -0,0 +1 @@ +30 3 * * * /usr/bin/rdist -f /etc/Distfile >& /var/log/rdist/rdist.err 2>&1 diff --git a/usr.bin/rdist/defs.h b/usr.bin/rdist/defs.h new file mode 100644 index 0000000..08bf8d6 --- /dev/null +++ b/usr.bin/rdist/defs.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)defs.h 8.1 (Berkeley) 6/9/93 + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +/* + * The version number should be changed whenever the protocol changes. + */ +#define VERSION 3 + + /* defines for yacc */ +#define EQUAL 1 +#define LP 2 +#define RP 3 +#define SM 4 +#define ARROW 5 +#define COLON 6 +#define DCOLON 7 +#define NAME 8 +#define STRING 9 +#define INSTALL 10 +#define NOTIFY 11 +#define EXCEPT 12 +#define PATTERN 13 +#define SPECIAL 14 +#define OPTION 15 + + /* lexical definitions */ +#define QUOTE 0200 /* used internally for quoted characters */ +#define TRIM 0177 /* Mask to strip quote bit */ + + /* table sizes */ +#define HASHSIZE 1021 +#define INMAX 3500 + + /* option flags */ +#define VERIFY 0x1 +#define WHOLE 0x2 +#define YOUNGER 0x4 +#define COMPARE 0x8 +#define REMOVE 0x10 +#define FOLLOW 0x20 +#define IGNLNKS 0x40 + + /* expand type definitions */ +#define E_VARS 0x1 +#define E_SHELL 0x2 +#define E_TILDE 0x4 +#define E_ALL 0x7 + + /* actions for lookup() */ +#define LOOKUP 0 +#define INSERT 1 +#define REPLACE 2 + +#define ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +#define ALLOC(x) (struct x *) malloc(sizeof(struct x)) + +struct namelist { /* for making lists of strings */ + char *n_name; + struct namelist *n_next; +}; + +struct subcmd { + short sc_type; /* type - INSTALL,NOTIFY,EXCEPT,SPECIAL */ + short sc_options; + char *sc_name; + struct namelist *sc_args; + struct subcmd *sc_next; +}; + +struct cmd { + int c_type; /* type - ARROW,DCOLON */ + char *c_name; /* hostname or time stamp file name */ + char *c_label; /* label for partial update */ + struct namelist *c_files; + struct subcmd *c_cmds; + struct cmd *c_next; +}; + +struct linkbuf { + ino_t inum; + dev_t devnum; + int count; + char pathname[BUFSIZ]; + char target[BUFSIZ]; + struct linkbuf *nextp; +}; + +extern int debug; /* debugging flag */ +extern int nflag; /* NOP flag, don't execute commands */ +extern int qflag; /* Quiet. don't print messages */ +extern int options; /* global options */ + +extern int nerrs; /* number of errors seen */ +extern int rem; /* remote file descriptor */ +extern int iamremote; /* acting as remote server */ +extern char tempfile[]; /* file name for logging changes */ +extern struct linkbuf *ihead; /* list of files with more than one link */ +extern struct passwd *pw; /* pointer to static area used by getpwent */ +extern struct group *gr; /* pointer to static area used by getgrent */ +extern char host[]; /* host name of master copy */ +extern char buf[]; /* general purpose buffer */ + +int any __P((int, char *)); +char *colon __P((char *)); +void cleanup __P((int)); +void define __P((char *)); +void docmds __P((char **, int, char **)); +void error __P((const char *, ...)); +int except __P((char *)); +struct namelist * + expand __P((struct namelist *, int)); +char *exptilde __P((char [], char *)); +void fatal __P((const char *, ...)); +int inlist __P((struct namelist *, char *)); +void insert __P((char *, + struct namelist *, struct namelist *, struct subcmd *)); +void install __P((char *, char *, int, int)); +void log __P((FILE *, const char *, ...)); +struct namelist * + lookup __P((char *, int, struct namelist *)); +void lostconn __P((int)); +struct namelist * + makenl __P((char *)); +struct subcmd * + makesubcmd __P((int)); +void prnames __P((struct namelist *)); +void server __P((void)); +void yyerror __P((char *)); +int yyparse __P((void)); diff --git a/usr.bin/rdist/docmd.c b/usr.bin/rdist/docmd.c new file mode 100644 index 0000000..0422a37 --- /dev/null +++ b/usr.bin/rdist/docmd.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)docmd.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include "defs.h" +#include +#include + +FILE *lfp; /* log file for recording files updated */ +struct subcmd *subcmds; /* list of sub-commands for current cmd */ +jmp_buf env; + +static int makeconn __P((char *)); +static int okname __P((char *)); +static void closeconn __P((void)); +static void cmptime __P((char *)); +static void doarrow __P((char **, + struct namelist *, char *, struct subcmd *)); +static void dodcolon __P((char **, + struct namelist *, char *, struct subcmd *)); +static void notify __P((char *, char *, struct namelist *, time_t)); +static void rcmptime __P((struct stat *)); + +/* + * Do the commands in cmds (initialized by yyparse). + */ +void +docmds(dhosts, argc, argv) + char **dhosts; + int argc; + char **argv; +{ + register struct cmd *c; + register struct namelist *f; + register char **cpp; + extern struct cmd *cmds; + + signal(SIGHUP, cleanup); + signal(SIGINT, cleanup); + signal(SIGQUIT, cleanup); + signal(SIGTERM, cleanup); + + for (c = cmds; c != NULL; c = c->c_next) { + if (dhosts != NULL && *dhosts != NULL) { + for (cpp = dhosts; *cpp; cpp++) + if (strcmp(c->c_name, *cpp) == 0) + goto fndhost; + continue; + } + fndhost: + if (argc) { + for (cpp = argv; *cpp; cpp++) { + if (c->c_label != NULL && + strcmp(c->c_label, *cpp) == 0) { + cpp = NULL; + goto found; + } + for (f = c->c_files; f != NULL; f = f->n_next) + if (strcmp(f->n_name, *cpp) == 0) + goto found; + } + continue; + } else + cpp = NULL; + found: + switch (c->c_type) { + case ARROW: + doarrow(cpp, c->c_files, c->c_name, c->c_cmds); + break; + case DCOLON: + dodcolon(cpp, c->c_files, c->c_name, c->c_cmds); + break; + default: + fatal("illegal command type %d\n", c->c_type); + } + } + closeconn(); +} + +/* + * Process commands for sending files to other machines. + */ +static void +doarrow(filev, files, rhost, cmds) + char **filev; + struct namelist *files; + char *rhost; + struct subcmd *cmds; +{ + register struct namelist *f; + register struct subcmd *sc; + register char **cpp; + int n, ddir, opts = options; + + if (debug) + printf("doarrow(%x, %s, %x)\n", files, rhost, cmds); + + if (files == NULL) { + error("no files to be updated\n"); + return; + } + + subcmds = cmds; + ddir = files->n_next != NULL; /* destination is a directory */ + if (nflag) + printf("updating host %s\n", rhost); + else { + if (setjmp(env)) + goto done; + signal(SIGPIPE, lostconn); + if (!makeconn(rhost)) + return; + if ((lfp = fopen(tempfile, "w")) == NULL) { + fatal("cannot open %s\n", tempfile); + exit(1); + } + } + for (f = files; f != NULL; f = f->n_next) { + if (filev) { + for (cpp = filev; *cpp; cpp++) + if (strcmp(f->n_name, *cpp) == 0) + goto found; + if (!nflag) + (void) fclose(lfp); + continue; + } + found: + n = 0; + for (sc = cmds; sc != NULL; sc = sc->sc_next) { + if (sc->sc_type != INSTALL) + continue; + n++; + install(f->n_name, sc->sc_name, + sc->sc_name == NULL ? 0 : ddir, sc->sc_options); + opts = sc->sc_options; + } + if (n == 0) + install(f->n_name, NULL, 0, options); + } +done: + if (!nflag) { + (void) signal(SIGPIPE, cleanup); + (void) fclose(lfp); + lfp = NULL; + } + for (sc = cmds; sc != NULL; sc = sc->sc_next) + if (sc->sc_type == NOTIFY) + notify(tempfile, rhost, sc->sc_args, 0); + if (!nflag) { + (void) unlink(tempfile); + for (; ihead != NULL; ihead = ihead->nextp) { + free(ihead); + if ((opts & IGNLNKS) || ihead->count == 0) + continue; + log(lfp, "%s: Warning: missing links\n", + ihead->pathname); + } + } +} + +/* + * Create a connection to the rdist server on the machine rhost. + */ +static int +makeconn(rhost) + char *rhost; +{ + register char *ruser, *cp; + static char *cur_host = NULL; + static int port = -1; + char tuser[20]; + int n; + extern char user[]; + extern int userid; + + if (debug) + printf("makeconn(%s)\n", rhost); + + if (cur_host != NULL && rem >= 0) { + if (strcmp(cur_host, rhost) == 0) + return(1); + closeconn(); + } + cur_host = rhost; + cp = index(rhost, '@'); + if (cp != NULL) { + char c = *cp; + + *cp = '\0'; + strncpy(tuser, rhost, sizeof(tuser)-1); + *cp = c; + rhost = cp + 1; + ruser = tuser; + if (*ruser == '\0') + ruser = user; + else if (!okname(ruser)) + return(0); + } else + ruser = user; + if (!qflag) + printf("updating host %s\n", rhost); + (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : ""); + if (port < 0) { + struct servent *sp; + + if ((sp = getservbyname("shell", "tcp")) == NULL) + fatal("shell/tcp: unknown service"); + port = sp->s_port; + } + + if (debug) { + printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser); + printf("buf = %s\n", buf); + } + + fflush(stdout); + seteuid(0); + rem = rcmd(&rhost, port, user, ruser, buf, 0); + seteuid(userid); + if (rem < 0) + return(0); + cp = buf; + if (read(rem, cp, 1) != 1) + lostconn(0); + if (*cp == 'V') { + do { + if (read(rem, cp, 1) != 1) + lostconn(0); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + *--cp = '\0'; + cp = buf; + n = 0; + while (*cp >= '0' && *cp <= '9') + n = (n * 10) + (*cp++ - '0'); + if (*cp == '\0' && n == VERSION) + return(1); + error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n); + } else { + error("connection failed: version numbers don't match\n"); + error("got unexpected input:"); + do { + error("%c", *cp); + } while (*cp != '\n' && read(rem, cp, 1) == 1); + } + closeconn(); + return(0); +} + +/* + * Signal end of previous connection. + */ +static void +closeconn() +{ + if (debug) + printf("closeconn()\n"); + + if (rem >= 0) { + (void) write(rem, "\2\n", 2); + (void) close(rem); + rem = -1; + } +} + +void +lostconn(signo) + int signo; +{ + if (iamremote) + cleanup(0); + log(lfp, "rdist: lost connection\n"); + longjmp(env, 1); +} + +static int +okname(name) + register char *name; +{ + register char *cp = name; + register int c; + + do { + c = *cp; + if (c & 0200) + goto bad; + if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') + goto bad; + cp++; + } while (*cp); + return(1); +bad: + error("invalid user name %s\n", name); + return(0); +} + +time_t lastmod; +FILE *tfp; +extern char target[], *tp; + +/* + * Process commands for comparing files to time stamp files. + */ +static void +dodcolon(filev, files, stamp, cmds) + char **filev; + struct namelist *files; + char *stamp; + struct subcmd *cmds; +{ + register struct subcmd *sc; + register struct namelist *f; + register char **cpp; + struct timeval tv[2]; + struct timezone tz; + struct stat stb; + + if (debug) + printf("dodcolon()\n"); + + if (files == NULL) { + error("no files to be updated\n"); + return; + } + if (stat(stamp, &stb) < 0) { + error("%s: %s\n", stamp, strerror(errno)); + return; + } + if (debug) + printf("%s: %ld\n", stamp, stb.st_mtime); + + subcmds = cmds; + lastmod = stb.st_mtime; + if (nflag || (options & VERIFY)) + tfp = NULL; + else { + if ((tfp = fopen(tempfile, "w")) == NULL) { + error("%s: %s\n", stamp, strerror(errno)); + return; + } + (void) gettimeofday(&tv[0], &tz); + tv[1] = tv[0]; + (void) utimes(stamp, tv); + } + + for (f = files; f != NULL; f = f->n_next) { + if (filev) { + for (cpp = filev; *cpp; cpp++) + if (strcmp(f->n_name, *cpp) == 0) + goto found; + continue; + } + found: + tp = NULL; + cmptime(f->n_name); + } + + if (tfp != NULL) + (void) fclose(tfp); + for (sc = cmds; sc != NULL; sc = sc->sc_next) + if (sc->sc_type == NOTIFY) + notify(tempfile, NULL, sc->sc_args, lastmod); + if (!nflag && !(options & VERIFY)) + (void) unlink(tempfile); +} + +/* + * Compare the mtime of file to the list of time stamps. + */ +static void +cmptime(name) + char *name; +{ + struct stat stb; + + if (debug) + printf("cmptime(%s)\n", name); + + if (except(name)) + return; + + if (nflag) { + printf("comparing dates: %s\n", name); + return; + } + + /* + * first time cmptime() is called? + */ + if (tp == NULL) { + if (exptilde(target, name) == NULL) + return; + tp = name = target; + while (*tp) + tp++; + } + if (access(name, 4) < 0 || stat(name, &stb) < 0) { + error("%s: %s\n", name, strerror(errno)); + return; + } + + switch (stb.st_mode & S_IFMT) { + case S_IFREG: + break; + + case S_IFDIR: + rcmptime(&stb); + return; + + default: + error("%s: not a plain file\n", name); + return; + } + + if (stb.st_mtime > lastmod) + log(tfp, "new: %s\n", name); +} + +static void +rcmptime(st) + struct stat *st; +{ + register DIR *d; + register struct direct *dp; + register char *cp; + char *otp; + int len; + + if (debug) + printf("rcmptime(%x)\n", st); + + if ((d = opendir(target)) == NULL) { + error("%s: %s\n", target, strerror(errno)); + return; + } + otp = tp; + len = tp - target; + while (dp = readdir(d)) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { + error("%s/%s: Name too long\n", target, dp->d_name); + continue; + } + tp = otp; + *tp++ = '/'; + cp = dp->d_name; + while (*tp++ = *cp++) + ; + tp--; + cmptime(target); + } + closedir(d); + tp = otp; + *tp = '\0'; +} + +/* + * Notify the list of people the changes that were made. + * rhost == NULL if we are mailing a list of changes compared to at time + * stamp file. + */ +static void +notify(file, rhost, to, lmod) + char *file, *rhost; + register struct namelist *to; + time_t lmod; +{ + register int fd, len; + struct stat stb; + FILE *pf; + + if ((options & VERIFY) || to == NULL) + return; + if (!qflag) { + printf("notify "); + if (rhost) + printf("@%s ", rhost); + prnames(to); + } + if (nflag) + return; + + if ((fd = open(file, 0)) < 0) { + error("%s: %s\n", file, strerror(errno)); + return; + } + if (fstat(fd, &stb) < 0) { + error("%s: %s\n", file, strerror(errno)); + (void) close(fd); + return; + } + if (stb.st_size == 0) { + (void) close(fd); + return; + } + /* + * Create a pipe to mailling program. + */ + (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL); + pf = popen(buf, "w"); + if (pf == NULL) { + error("notify: \"%s\" failed\n", _PATH_SENDMAIL); + (void) close(fd); + return; + } + /* + * Output the proper header information. + */ + fprintf(pf, "From: rdist (Remote distribution program)\n"); + fprintf(pf, "To:"); + if (!any('@', to->n_name) && rhost != NULL) + fprintf(pf, " %s@%s", to->n_name, rhost); + else + fprintf(pf, " %s", to->n_name); + to = to->n_next; + while (to != NULL) { + if (!any('@', to->n_name) && rhost != NULL) + fprintf(pf, ", %s@%s", to->n_name, rhost); + else + fprintf(pf, ", %s", to->n_name); + to = to->n_next; + } + putc('\n', pf); + if (rhost != NULL) + fprintf(pf, "Subject: files updated by rdist from %s to %s\n", + host, rhost); + else + fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod)); + putc('\n', pf); + + while ((len = read(fd, buf, BUFSIZ)) > 0) + (void) fwrite(buf, 1, len, pf); + (void) close(fd); + (void) pclose(pf); +} + +/* + * Return true if name is in the list. + */ +int +inlist(list, file) + struct namelist *list; + char *file; +{ + register struct namelist *nl; + + for (nl = list; nl != NULL; nl = nl->n_next) + if (!strcmp(file, nl->n_name)) + return(1); + return(0); +} + +/* + * Return TRUE if file is in the exception list. + */ +int +except(file) + char *file; +{ + register struct subcmd *sc; + register struct namelist *nl; + + if (debug) + printf("except(%s)\n", file); + + for (sc = subcmds; sc != NULL; sc = sc->sc_next) { + if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN) + continue; + for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) { + if (sc->sc_type == EXCEPT) { + if (!strcmp(file, nl->n_name)) + return(1); + continue; + } + re_comp(nl->n_name); + if (re_exec(file) > 0) + return(1); + } + } + return(0); +} + +char * +colon(cp) + register char *cp; +{ + + while (*cp) { + if (*cp == ':') + return(cp); + if (*cp == '/') + return(0); + cp++; + } + return(0); +} diff --git a/usr.bin/rdist/expand.c b/usr.bin/rdist/expand.c new file mode 100644 index 0000000..6b5fd17 --- /dev/null +++ b/usr.bin/rdist/expand.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include "defs.h" + +#define GAVSIZ NCARGS / 6 +#define LC '{' +#define RC '}' + +static char shchars[] = "${[*?"; + +int which; /* bit mask of types to expand */ +int eargc; /* expanded arg count */ +char **eargv; /* expanded arg vectors */ +char *path; +char *pathp; +char *lastpathp; +char *tilde; /* "~user" if not expanding tilde, else "" */ +char *tpathp; +int nleft; + +int expany; /* any expansions done? */ +char *entp; +char **sortbase; + +#define sort() qsort((char *)sortbase, &eargv[eargc] - sortbase, \ + sizeof(*sortbase), argcmp), sortbase = &eargv[eargc] + +static void Cat __P((char *, char *)); +static void addpath __P((int)); +static int amatch __P((char *, char *)); +static int argcmp __P((const void *, const void *)); +static int execbrc __P((char *, char *)); +static void expsh __P((char *)); +static void expstr __P((char *)); +static int match __P((char *, char *)); +static void matchdir __P((char *)); +static int smatch __P((char *, char *)); + +/* + * Take a list of names and expand any macros, etc. + * wh = E_VARS if expanding variables. + * wh = E_SHELL if expanding shell characters. + * wh = E_TILDE if expanding `~'. + * or any of these or'ed together. + * + * Major portions of this were snarfed from csh/sh.glob.c. + */ +struct namelist * +expand(list, wh) + struct namelist *list; + int wh; +{ + register struct namelist *nl, *prev; + register int n; + char pathbuf[BUFSIZ]; + char *argvbuf[GAVSIZ]; + + if (debug) { + printf("expand(%x, %d)\nlist = ", list, wh); + prnames(list); + } + + if (wh == 0) { + register char *cp; + + for (nl = list; nl != NULL; nl = nl->n_next) + for (cp = nl->n_name; *cp; cp++) + *cp = *cp & TRIM; + return(list); + } + + which = wh; + path = tpathp = pathp = pathbuf; + *pathp = '\0'; + lastpathp = &path[sizeof pathbuf - 2]; + tilde = ""; + eargc = 0; + eargv = sortbase = argvbuf; + *eargv = 0; + nleft = NCARGS - 4; + /* + * Walk the name list and expand names into eargv[]; + */ + for (nl = list; nl != NULL; nl = nl->n_next) + expstr(nl->n_name); + /* + * Take expanded list of names from eargv[] and build a new list. + */ + list = prev = NULL; + for (n = 0; n < eargc; n++) { + nl = makenl(NULL); + nl->n_name = eargv[n]; + if (prev == NULL) + list = prev = nl; + else { + prev->n_next = nl; + prev = nl; + } + } + if (debug) { + printf("expanded list = "); + prnames(list); + } + return(list); +} + +static void +expstr(s) + char *s; +{ + register char *cp, *cp1; + register struct namelist *tp; + char *tail; + char buf[BUFSIZ]; + int savec, oeargc; + extern char homedir[]; + + if (s == NULL || *s == '\0') + return; + + if ((which & E_VARS) && (cp = index(s, '$')) != NULL) { + *cp++ = '\0'; + if (*cp == '\0') { + yyerror("no variable name after '$'"); + return; + } + if (*cp == LC) { + cp++; + if ((tail = index(cp, RC)) == NULL) { + yyerror("unmatched '{'"); + return; + } + *tail++ = savec = '\0'; + if (*cp == '\0') { + yyerror("no variable name after '$'"); + return; + } + } else { + tail = cp + 1; + savec = *tail; + *tail = '\0'; + } + tp = lookup(cp, NULL, 0); + if (savec != '\0') + *tail = savec; + if (tp != NULL) { + for (; tp != NULL; tp = tp->n_next) { + sprintf(buf, "%s%s%s", s, tp->n_name, tail); + expstr(buf); + } + return; + } + sprintf(buf, "%s%s", s, tail); + expstr(buf); + return; + } + if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) { + Cat(s, ""); + sort(); + return; + } + if (*s == '~') { + cp = ++s; + if (*cp == '\0' || *cp == '/') { + tilde = "~"; + cp1 = homedir; + } else { + tilde = cp1 = buf; + *cp1++ = '~'; + do + *cp1++ = *cp++; + while (*cp && *cp != '/'); + *cp1 = '\0'; + if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) { + if ((pw = getpwnam(buf+1)) == NULL) { + strcat(buf, ": unknown user name"); + yyerror(buf+1); + return; + } + } + cp1 = pw->pw_dir; + s = cp; + } + for (cp = path; *cp++ = *cp1++; ) + ; + tpathp = pathp = cp - 1; + } else { + tpathp = pathp = path; + tilde = ""; + } + *pathp = '\0'; + if (!(which & E_SHELL)) { + if (which & E_TILDE) + Cat(path, s); + else + Cat(tilde, s); + sort(); + return; + } + oeargc = eargc; + expany = 0; + expsh(s); + if (eargc == oeargc) + Cat(s, ""); /* "nonomatch" is set */ + sort(); +} + +static int +argcmp(a1, a2) + const void *a1, *a2; +{ + + return (strcmp(*(char **)a1, *(char **)a2)); +} + +/* + * If there are any Shell meta characters in the name, + * expand into a list, after searching directory + */ +static void +expsh(s) + char *s; +{ + register char *cp; + register char *spathp, *oldcp; + struct stat stb; + + spathp = pathp; + cp = s; + while (!any(*cp, shchars)) { + if (*cp == '\0') { + if (!expany || stat(path, &stb) >= 0) { + if (which & E_TILDE) + Cat(path, ""); + else + Cat(tilde, tpathp); + } + goto endit; + } + addpath(*cp++); + } + oldcp = cp; + while (cp > s && *cp != '/') + cp--, pathp--; + if (*cp == '/') + cp++, pathp++; + *pathp = '\0'; + if (*oldcp == '{') { + execbrc(cp, NULL); + return; + } + matchdir(cp); +endit: + pathp = spathp; + *pathp = '\0'; +} + +static void +matchdir(pattern) + char *pattern; +{ + struct stat stb; + register struct direct *dp; + DIR *dirp; + + dirp = opendir(path); + if (dirp == NULL) { + if (expany) + return; + goto patherr2; + } + if (fstat(dirp->dd_fd, &stb) < 0) + goto patherr1; + if (!ISDIR(stb.st_mode)) { + errno = ENOTDIR; + goto patherr1; + } + while ((dp = readdir(dirp)) != NULL) + if (match(dp->d_name, pattern)) { + if (which & E_TILDE) + Cat(path, dp->d_name); + else { + strcpy(pathp, dp->d_name); + Cat(tilde, tpathp); + *pathp = '\0'; + } + } + closedir(dirp); + return; + +patherr1: + closedir(dirp); +patherr2: + strcat(path, ": "); + strcat(path, strerror(errno)); + yyerror(path); +} + +static int +execbrc(p, s) + char *p, *s; +{ + char restbuf[BUFSIZ + 2]; + register char *pe, *pm, *pl; + int brclev = 0; + char *lm, savec, *spathp; + + for (lm = restbuf; *p != '{'; *lm++ = *p++) + continue; + for (pe = ++p; *pe; pe++) + switch (*pe) { + + case '{': + brclev++; + continue; + + case '}': + if (brclev == 0) + goto pend; + brclev--; + continue; + + case '[': + for (pe++; *pe && *pe != ']'; pe++) + continue; + if (!*pe) + yyerror("Missing ']'"); + continue; + } +pend: + if (brclev || !*pe) { + yyerror("Missing '}'"); + return (0); + } + for (pl = pm = p; pm <= pe; pm++) + switch (*pm & (QUOTE|TRIM)) { + + case '{': + brclev++; + continue; + + case '}': + if (brclev) { + brclev--; + continue; + } + goto doit; + + case ',': + if (brclev) + continue; +doit: + savec = *pm; + *pm = 0; + strcpy(lm, pl); + strcat(restbuf, pe + 1); + *pm = savec; + if (s == 0) { + spathp = pathp; + expsh(restbuf); + pathp = spathp; + *pathp = 0; + } else if (amatch(s, restbuf)) + return (1); + sort(); + pl = pm + 1; + continue; + + case '[': + for (pm++; *pm && *pm != ']'; pm++) + continue; + if (!*pm) + yyerror("Missing ']'"); + continue; + } + return (0); +} + +static int +match(s, p) + char *s, *p; +{ + register int c; + register char *sentp; + char sexpany = expany; + + if (*s == '.' && *p != '.') + return (0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + expany = sexpany; + return (c); +} + +static int +amatch(s, p) + register char *s, *p; +{ + register int scc; + int ok, lc; + char *spathp; + struct stat stb; + int c, cc; + + expany = 1; + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + + case '{': + return (execbrc(p - 1, s - 1)); + + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) { + yyerror("Missing ']'"); + return (0); + } + continue; + + case '*': + if (!*p) + return (1); + if (*p == '/') { + p++; + goto slash; + } + for (s--; *s; s++) + if (amatch(s, p)) + return (1); + return (0); + + case '\0': + return (scc == '\0'); + + default: + if ((c & TRIM) != scc) + return (0); + continue; + + case '?': + if (scc == '\0') + return (0); + continue; + + case '/': + if (scc) + return (0); +slash: + s = entp; + spathp = pathp; + while (*s) + addpath(*s++); + addpath('/'); + if (stat(path, &stb) == 0 && ISDIR(stb.st_mode)) + if (*p == '\0') { + if (which & E_TILDE) + Cat(path, ""); + else + Cat(tilde, tpathp); + } else + expsh(p); + pathp = spathp; + *pathp = '\0'; + return (0); + } + } +} + +static int +smatch(s, p) + register char *s, *p; +{ + register int scc; + int ok, lc; + int c, cc; + + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) { + yyerror("Missing ']'"); + return (0); + } + continue; + + case '*': + if (!*p) + return (1); + for (s--; *s; s++) + if (smatch(s, p)) + return (1); + return (0); + + case '\0': + return (scc == '\0'); + + default: + if ((c & TRIM) != scc) + return (0); + continue; + + case '?': + if (scc == 0) + return (0); + continue; + + } + } +} + +static void +Cat(s1, s2) + register char *s1, *s2; +{ + int len = strlen(s1) + strlen(s2) + 1; + register char *s; + + nleft -= len; + if (nleft <= 0 || ++eargc >= GAVSIZ) + yyerror("Arguments too long"); + eargv[eargc] = 0; + eargv[eargc - 1] = s = malloc(len); + if (s == NULL) + fatal("ran out of memory\n"); + while (*s++ = *s1++ & TRIM) + ; + s--; + while (*s++ = *s2++ & TRIM) + ; +} + +static void +addpath(c) + int c; +{ + + if (pathp >= lastpathp) + yyerror("Pathname too long"); + else { + *pathp++ = c & TRIM; + *pathp = '\0'; + } +} + +/* + * Expand file names beginning with `~' into the + * user's home directory path name. Return a pointer in buf to the + * part corresponding to `file'. + */ +char * +exptilde(buf, file) + char buf[]; + register char *file; +{ + register char *s1, *s2, *s3; + extern char homedir[]; + + if (*file != '~') { + strcpy(buf, file); + return(buf); + } + if (*++file == '\0') { + s2 = homedir; + s3 = NULL; + } else if (*file == '/') { + s2 = homedir; + s3 = file; + } else { + s3 = file; + while (*s3 && *s3 != '/') + s3++; + if (*s3 == '/') + *s3 = '\0'; + else + s3 = NULL; + if (pw == NULL || strcmp(pw->pw_name, file) != 0) { + if ((pw = getpwnam(file)) == NULL) { + error("%s: unknown user name\n", file); + if (s3 != NULL) + *s3 = '/'; + return(NULL); + } + } + if (s3 != NULL) + *s3 = '/'; + s2 = pw->pw_dir; + } + for (s1 = buf; *s1++ = *s2++; ) + ; + s2 = --s1; + if (s3 != NULL) { + s2++; + while (*s1++ = *s3++) + ; + } + return(s2); +} diff --git a/usr.bin/rdist/gram.y b/usr.bin/rdist/gram.y new file mode 100644 index 0000000..7f40f87 --- /dev/null +++ b/usr.bin/rdist/gram.y @@ -0,0 +1,508 @@ +%{ +/* + * Copyright (c) 1983, 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[] = "@(#)gram.y 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include "defs.h" + +struct cmd *cmds = NULL; +struct cmd *last_cmd; +struct namelist *last_n; +struct subcmd *last_sc; + +static char *makestr __P((char *)); + +%} + +%term EQUAL 1 +%term LP 2 +%term RP 3 +%term SM 4 +%term ARROW 5 +%term COLON 6 +%term DCOLON 7 +%term NAME 8 +%term STRING 9 +%term INSTALL 10 +%term NOTIFY 11 +%term EXCEPT 12 +%term PATTERN 13 +%term SPECIAL 14 +%term OPTION 15 + +%union { + int intval; + char *string; + struct subcmd *subcmd; + struct namelist *namel; +} + +%type OPTION, options +%type NAME, STRING +%type INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd +%type namelist, names, opt_namelist + +%% + +file: /* VOID */ + | file command + ; + +command: NAME EQUAL namelist = { + (void) lookup($1, INSERT, $3); + } + | namelist ARROW namelist cmdlist = { + insert(NULL, $1, $3, $4); + } + | NAME COLON namelist ARROW namelist cmdlist = { + insert($1, $3, $5, $6); + } + | namelist DCOLON NAME cmdlist = { + append(NULL, $1, $3, $4); + } + | NAME COLON namelist DCOLON NAME cmdlist = { + append($1, $3, $5, $6); + } + | error + ; + +namelist: NAME = { + $$ = makenl($1); + } + | LP names RP = { + $$ = $2; + } + ; + +names: /* VOID */ { + $$ = last_n = NULL; + } + | names NAME = { + if (last_n == NULL) + $$ = last_n = makenl($2); + else { + last_n->n_next = makenl($2); + last_n = last_n->n_next; + $$ = $1; + } + } + ; + +cmdlist: /* VOID */ { + $$ = last_sc = NULL; + } + | cmdlist cmd = { + if (last_sc == NULL) + $$ = last_sc = $2; + else { + last_sc->sc_next = $2; + last_sc = $2; + $$ = $1; + } + } + ; + +cmd: INSTALL options opt_namelist SM = { + register struct namelist *nl; + + $1->sc_options = $2 | options; + if ($3 != NULL) { + nl = expand($3, E_VARS); + if (nl) { + if (nl->n_next != NULL) + yyerror("only one name allowed\n"); + $1->sc_name = nl->n_name; + free(nl); + } else + $1->sc_name = NULL; + } + $$ = $1; + } + | NOTIFY namelist SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_VARS); + $$ = $1; + } + | EXCEPT namelist SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_ALL); + $$ = $1; + } + | PATTERN namelist SM = { + struct namelist *nl; + char *cp, *re_comp(); + + for (nl = $2; nl != NULL; nl = nl->n_next) + if ((cp = re_comp(nl->n_name)) != NULL) + yyerror(cp); + $1->sc_args = expand($2, E_VARS); + $$ = $1; + } + | SPECIAL opt_namelist STRING SM = { + if ($2 != NULL) + $1->sc_args = expand($2, E_ALL); + $1->sc_name = $3; + $$ = $1; + } + ; + +options: /* VOID */ = { + $$ = 0; + } + | options OPTION = { + $$ |= $2; + } + ; + +opt_namelist: /* VOID */ = { + $$ = NULL; + } + | namelist = { + $$ = $1; + } + ; + +%% + +int yylineno = 1; +extern FILE *fin; + +int +yylex() +{ + static char yytext[INMAX]; + register int c; + register char *cp1, *cp2; + static char quotechars[] = "[]{}*?$"; + +again: + switch (c = getc(fin)) { + case EOF: /* end of file */ + return(0); + + case '#': /* start of comment */ + while ((c = getc(fin)) != EOF && c != '\n') + ; + if (c == EOF) + return(0); + case '\n': + yylineno++; + case ' ': + case '\t': /* skip blanks */ + goto again; + + case '=': /* EQUAL */ + return(EQUAL); + + case '(': /* LP */ + return(LP); + + case ')': /* RP */ + return(RP); + + case ';': /* SM */ + return(SM); + + case '-': /* -> */ + if ((c = getc(fin)) == '>') + return(ARROW); + ungetc(c, fin); + c = '-'; + break; + + case '"': /* STRING */ + cp1 = yytext; + cp2 = &yytext[INMAX - 1]; + for (;;) { + if (cp1 >= cp2) { + yyerror("command string too long\n"); + break; + } + c = getc(fin); + if (c == EOF || c == '"') + break; + if (c == '\\') { + if ((c = getc(fin)) == EOF) { + *cp1++ = '\\'; + break; + } + } + if (c == '\n') { + yylineno++; + c = ' '; /* can't send '\n' */ + } + *cp1++ = c; + } + if (c != '"') + yyerror("missing closing '\"'\n"); + *cp1 = '\0'; + yylval.string = makestr(yytext); + return(STRING); + + case ':': /* : or :: */ + if ((c = getc(fin)) == ':') + return(DCOLON); + ungetc(c, fin); + return(COLON); + } + cp1 = yytext; + cp2 = &yytext[INMAX - 1]; + for (;;) { + if (cp1 >= cp2) { + yyerror("input line too long\n"); + break; + } + if (c == '\\') { + if ((c = getc(fin)) != EOF) { + if (any(c, quotechars)) + c |= QUOTE; + } else { + *cp1++ = '\\'; + break; + } + } + *cp1++ = c; + c = getc(fin); + if (c == EOF || any(c, " \"'\t()=;:\n")) { + ungetc(c, fin); + break; + } + } + *cp1 = '\0'; + if (yytext[0] == '-' && yytext[2] == '\0') { + switch (yytext[1]) { + case 'b': + yylval.intval = COMPARE; + return(OPTION); + + case 'R': + yylval.intval = REMOVE; + return(OPTION); + + case 'v': + yylval.intval = VERIFY; + return(OPTION); + + case 'w': + yylval.intval = WHOLE; + return(OPTION); + + case 'y': + yylval.intval = YOUNGER; + return(OPTION); + + case 'h': + yylval.intval = FOLLOW; + return(OPTION); + + case 'i': + yylval.intval = IGNLNKS; + return(OPTION); + } + } + if (!strcmp(yytext, "install")) + c = INSTALL; + else if (!strcmp(yytext, "notify")) + c = NOTIFY; + else if (!strcmp(yytext, "except")) + c = EXCEPT; + else if (!strcmp(yytext, "except_pat")) + c = PATTERN; + else if (!strcmp(yytext, "special")) + c = SPECIAL; + else { + yylval.string = makestr(yytext); + return(NAME); + } + yylval.subcmd = makesubcmd(c); + return(c); +} + +int +any(c, str) + register int c; + register char *str; +{ + while (*str) + if (c == *str++) + return(1); + return(0); +} + +/* + * Insert or append ARROW command to list of hosts to be updated. + */ +void +insert(label, files, hosts, subcmds) + char *label; + struct namelist *files, *hosts; + struct subcmd *subcmds; +{ + register struct cmd *c, *prev, *nc; + register struct namelist *h; + + files = expand(files, E_VARS|E_SHELL); + hosts = expand(hosts, E_ALL); + for (h = hosts; h != NULL; free(h), h = h->n_next) { + /* + * Search command list for an update to the same host. + */ + for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { + if (strcmp(c->c_name, h->n_name) == 0) { + do { + prev = c; + c = c->c_next; + } while (c != NULL && + strcmp(c->c_name, h->n_name) == 0); + break; + } + } + /* + * Insert new command to update host. + */ + nc = ALLOC(cmd); + if (nc == NULL) + fatal("ran out of memory\n"); + nc->c_type = ARROW; + nc->c_name = h->n_name; + nc->c_label = label; + nc->c_files = files; + nc->c_cmds = subcmds; + nc->c_next = c; + if (prev == NULL) + cmds = nc; + else + prev->c_next = nc; + /* update last_cmd if appending nc to cmds */ + if (c == NULL) + last_cmd = nc; + } +} + +/* + * Append DCOLON command to the end of the command list since these are always + * executed in the order they appear in the distfile. + */ +void +append(label, files, stamp, subcmds) + char *label; + struct namelist *files; + char *stamp; + struct subcmd *subcmds; +{ + register struct cmd *c; + + c = ALLOC(cmd); + if (c == NULL) + fatal("ran out of memory\n"); + c->c_type = DCOLON; + c->c_name = stamp; + c->c_label = label; + c->c_files = expand(files, E_ALL); + c->c_cmds = subcmds; + c->c_next = NULL; + if (cmds == NULL) + cmds = last_cmd = c; + else { + last_cmd->c_next = c; + last_cmd = c; + } +} + +/* + * Error printing routine in parser. + */ +void +yyerror(s) + char *s; +{ + ++nerrs; + fflush(stdout); + fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); +} + +/* + * Return a copy of the string. + */ +static char * +makestr(str) + char *str; +{ + register char *cp, *s; + + str = cp = malloc(strlen(s = str) + 1); + if (cp == NULL) + fatal("ran out of memory\n"); + while (*cp++ = *s++) + ; + return(str); +} + +/* + * Allocate a namelist structure. + */ +struct namelist * +makenl(name) + char *name; +{ + register struct namelist *nl; + + nl = ALLOC(namelist); + if (nl == NULL) + fatal("ran out of memory\n"); + nl->n_name = name; + nl->n_next = NULL; + return(nl); +} + +/* + * Make a sub command for lists of variables, commands, etc. + */ +struct subcmd * +makesubcmd(type) + int type; +{ + register struct subcmd *sc; + + sc = ALLOC(subcmd); + if (sc == NULL) + fatal("ran out of memory\n"); + sc->sc_type = type; + sc->sc_args = NULL; + sc->sc_next = NULL; + sc->sc_name = NULL; + return(sc); +} diff --git a/usr.bin/rdist/lookup.c b/usr.bin/rdist/lookup.c new file mode 100644 index 0000000..9819e68 --- /dev/null +++ b/usr.bin/rdist/lookup.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)lookup.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include "defs.h" + + /* symbol types */ +#define VAR 1 +#define CONST 2 + +struct syment { + int s_type; + char *s_name; + struct namelist *s_value; + struct syment *s_next; +}; + +static struct syment *hashtab[HASHSIZE]; + +/* + * Define a variable from a command line argument. + */ +void +define(name) + char *name; +{ + register char *cp, *s; + register struct namelist *nl; + struct namelist *value; + + if (debug) + printf("define(%s)\n", name); + + cp = index(name, '='); + if (cp == NULL) + value = NULL; + else if (cp[1] == '\0') { + *cp = '\0'; + value = NULL; + } else if (cp[1] != '(') { + *cp++ = '\0'; + value = makenl(cp); + } else { + nl = NULL; + *cp++ = '\0'; + do + cp++; + while (*cp == ' ' || *cp == '\t'); + for (s = cp; ; s++) { + switch (*s) { + case ')': + *s = '\0'; + case '\0': + break; + case ' ': + case '\t': + *s++ = '\0'; + while (*s == ' ' || *s == '\t') + s++; + if (*s == ')') + *s = '\0'; + break; + default: + continue; + } + if (nl == NULL) + value = nl = makenl(cp); + else { + nl->n_next = makenl(cp); + nl = nl->n_next; + } + if (*s == '\0') + break; + cp = s; + } + } + (void) lookup(name, REPLACE, value); +} + +/* + * Lookup name in the table and return a pointer to it. + * LOOKUP - just do lookup, return NULL if not found. + * INSERT - insert name with value, error if already defined. + * REPLACE - insert or replace name with value. + */ + +struct namelist * +lookup(name, action, value) + char *name; + int action; + struct namelist *value; +{ + register unsigned n; + register char *cp; + register struct syment *s; + char buf[256]; + + if (debug) + printf("lookup(%s, %d, %x)\n", name, action, value); + + n = 0; + for (cp = name; *cp; ) + n += *cp++; + n %= HASHSIZE; + + for (s = hashtab[n]; s != NULL; s = s->s_next) { + if (strcmp(name, s->s_name)) + continue; + if (action != LOOKUP) { + if (action != INSERT || s->s_type != CONST) { + (void)sprintf(buf, "%s redefined", name); + yyerror(buf); + } + } + return(s->s_value); + } + + if (action == LOOKUP) { + (void)sprintf(buf, "%s undefined", name); + yyerror(buf); + return(NULL); + } + + s = ALLOC(syment); + if (s == NULL) + fatal("ran out of memory\n"); + s->s_next = hashtab[n]; + hashtab[n] = s; + s->s_type = action == INSERT ? VAR : CONST; + s->s_name = name; + s->s_value = value; + return(value); +} diff --git a/usr.bin/rdist/main.c b/usr.bin/rdist/main.c new file mode 100644 index 0000000..44b3279a --- /dev/null +++ b/usr.bin/rdist/main.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include "defs.h" + +#define NHOSTS 100 + +/* + * Remote distribution program. + */ + +char *distfile = NULL; +#define _RDIST_TMP "/rdistXXXXXX" +char tempfile[sizeof _PATH_TMP + sizeof _RDIST_TMP + 1]; +char *tempname; + +int debug; /* debugging flag */ +int nflag; /* NOP flag, just print commands without executing */ +int qflag; /* Quiet. Don't print messages */ +int options; /* global options */ +int iamremote; /* act as remote server for transfering files */ + +FILE *fin = NULL; /* input file pointer */ +int rem = -1; /* file descriptor to remote source/sink process */ +char host[32]; /* host name */ +int nerrs; /* number of errors while sending/receiving */ +char user[10]; /* user's name */ +char homedir[128]; /* user's home directory */ +int userid; /* user's user ID */ +int groupid; /* user's group ID */ + +struct passwd *pw; /* pointer to static area used by getpwent */ +struct group *gr; /* pointer to static area used by getgrent */ + +static void usage __P((void)); +static void docmdargs __P((int, char *[])); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char *arg; + int cmdargs = 0; + char *dhosts[NHOSTS], **hp = dhosts; + + pw = getpwuid(userid = getuid()); + if (pw == NULL) { + fprintf(stderr, "%s: Who are you?\n", argv[0]); + exit(1); + } + strcpy(user, pw->pw_name); + strcpy(homedir, pw->pw_dir); + groupid = pw->pw_gid; + gethostname(host, sizeof(host)); + strcpy(tempfile, _PATH_TMP); + strcat(tempfile, _RDIST_TMP); + if ((tempname = rindex(tempfile, '/')) != 0) + tempname++; + else + tempname = tempfile; + + while (--argc > 0) { + if ((arg = *++argv)[0] != '-') + break; + if (!strcmp(arg, "-Server")) + iamremote++; + else while (*++arg) + switch (*arg) { + case 'f': + if (--argc <= 0) + usage(); + distfile = *++argv; + if (distfile[0] == '-' && distfile[1] == '\0') + fin = stdin; + break; + + case 'm': + if (--argc <= 0) + usage(); + if (hp >= &dhosts[NHOSTS-2]) { + fprintf(stderr, "rdist: too many destination hosts\n"); + exit(1); + } + *hp++ = *++argv; + break; + + case 'd': + if (--argc <= 0) + usage(); + define(*++argv); + break; + + case 'D': + debug++; + break; + + case 'c': + cmdargs++; + break; + + case 'n': + if (options & VERIFY) { + printf("rdist: -n overrides -v\n"); + options &= ~VERIFY; + } + nflag++; + break; + + case 'q': + qflag++; + break; + + case 'b': + options |= COMPARE; + break; + + case 'R': + options |= REMOVE; + break; + + case 'v': + if (nflag) { + printf("rdist: -n overrides -v\n"); + break; + } + options |= VERIFY; + break; + + case 'w': + options |= WHOLE; + break; + + case 'y': + options |= YOUNGER; + break; + + case 'h': + options |= FOLLOW; + break; + + case 'i': + options |= IGNLNKS; + break; + + default: + usage(); + } + } + *hp = NULL; + + seteuid(userid); + mktemp(tempfile); + + if (iamremote) { + server(); + exit(nerrs != 0); + } + + if (cmdargs) + docmdargs(argc, argv); + else { + if (fin == NULL) { + if(distfile == NULL) { + if((fin = fopen("distfile","r")) == NULL) + fin = fopen("Distfile", "r"); + } else + fin = fopen(distfile, "r"); + if(fin == NULL) { + perror(distfile ? distfile : "distfile"); + exit(1); + } + } + yyparse(); + if (nerrs == 0) + docmds(dhosts, argc, argv); + } + + exit(nerrs != 0); +} + +static void +usage() +{ + printf("Usage: rdist [-nqbhirvwyD] [-f distfile] [-d var=value] [-m host] [file ...]\n"); + printf("or: rdist [-nqbhirvwyD] -c source [...] machine[:dest]\n"); + exit(1); +} + +/* + * rcp like interface for distributing files. + */ +static void +docmdargs(nargs, args) + int nargs; + char *args[]; +{ + register struct namelist *nl, *prev; + register char *cp; + struct namelist *files, *hosts; + struct subcmd *cmds; + char *dest; + static struct namelist tnl = { NULL, NULL }; + int i; + + if (nargs < 2) + usage(); + + prev = NULL; + for (i = 0; i < nargs - 1; i++) { + nl = makenl(args[i]); + if (prev == NULL) + files = prev = nl; + else { + prev->n_next = nl; + prev = nl; + } + } + + cp = args[i]; + if ((dest = index(cp, ':')) != NULL) + *dest++ = '\0'; + tnl.n_name = cp; + hosts = expand(&tnl, E_ALL); + if (nerrs) + exit(1); + + if (dest == NULL || *dest == '\0') + cmds = NULL; + else { + cmds = makesubcmd(INSTALL); + cmds->sc_options = options; + cmds->sc_name = dest; + } + + if (debug) { + printf("docmdargs()\nfiles = "); + prnames(files); + printf("hosts = "); + prnames(hosts); + } + insert(NULL, files, hosts, cmds); + docmds(NULL, 0, NULL); +} + +/* + * Print a list of NAME blocks (mostly for debugging). + */ +void +prnames(nl) + register struct namelist *nl; +{ + printf("( "); + while (nl != NULL) { + printf("%s ", nl->n_name); + nl = nl->n_next; + } + printf(")\n"); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +warn(const char *fmt, ...) +#else +warn(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + extern int yylineno; + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "rdist: line %d: Warning: ", yylineno); + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); + va_end(ap); +} diff --git a/usr.bin/rdist/pathnames.h b/usr.bin/rdist/pathnames.h new file mode 100644 index 0000000..2e1b067 --- /dev/null +++ b/usr.bin/rdist/pathnames.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/9/93 + */ + +#include + +#define _PATH_RDIST "rdist" diff --git a/usr.bin/rdist/rdist.1 b/usr.bin/rdist/rdist.1 new file mode 100644 index 0000000..9ae17e9 --- /dev/null +++ b/usr.bin/rdist/rdist.1 @@ -0,0 +1,412 @@ +.\" Copyright (c) 1985, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rdist.1 8.3 (Berkeley) 3/17/94 +.\" +.Dd March 17, 1994 +.Dt RDIST 1 +.Os BSD 4.3 +.Sh NAME +.Nm rdist +.Nd remote file distribution program +.Sh SYNOPSIS +.Nm rdist +.Op Fl nqbRhivwy +.Op Fl f Ar distfile +.Op Fl d Ar var=value +.Op Fl m Ar host +.Op Ar name ... +.Nm rdist +.Op Fl nqbRhivwy +.Fl c +.Ar name ... +.Oo login@ Oc Ns Ar host Ns Op :dest +.Sh DESCRIPTION +.Nm Rdist +is a program to maintain identical copies of files over multiple hosts. +It preserves the owner, group, mode, and mtime of files if possible and +can update programs that are executing. +.Nm Rdist +reads commands from +.Ar distfile +to direct the updating of files and/or directories. +.Pp +Options specific to the first SYNOPSIS form: +.Pp +.Bl -tag -width indent +.It Fl +If +.Ar distfile +is +.Sq Fl , +the standard input is used. +.It Fl f Ar distfile +Use the specified +.Ar distfile. +.El +.Pp +If either the +.Fl f +or +.Sq Fl +option is not specified, the program looks first for +.Dq Pa distfile , +then +.Dq Pa Distfile +to use as the input. +If no names are specified on the command line, +.Nm rdist +will update all of the files and directories listed in +.Ar distfile . +Otherwise, the argument is taken to be the name of a file to be updated +or the label of a command to execute. If label and file names conflict, +it is assumed to be a label. +These may be used together to update specific files +using specific commands. +.Pp +Options specific to the second SYNOPSIS form: +.Pp +.Bl -tag -width Fl c +.It Fl c +Forces +.Nm rdist +to interpret the remaining arguments as a small +.Ar distfile . +.Pp +The equivalent distfile is as follows. +.Pp +.Bd -filled -offset indent -compact +.Pq Ar name ... +.Li -> +.Op Ar login@ +.Ar host +.Bd -filled -offset indent -compact +.Li install +.Op Ar dest ; +.Ed +.Ed +.El +.Pp +Options common to both forms: +.Pp +.Bl -tag -width Ic +.It Fl b +Binary comparison. Perform a binary comparison and update files if they differ +rather than comparing dates and sizes. +.It Fl d Ar var=value +Define +.Ar var +to have +.Ar value . +The +.Fl d +option is used to define or override variable definitions in the +.Ar distfile . +.Ar Value +can be the empty string, one name, or a list of names surrounded by +parentheses and separated by tabs and/or spaces. +.It Fl h +Follow symbolic links. Copy the file that the link points to rather than the +link itself. +.It Fl i +Ignore unresolved links. +.Nm Rdist +will normally try to maintain the link structure of files being transferred +and warn the user if all the links cannot be found. +.It Fl m Ar host +Limit which machines are to be updated. Multiple +.Fl m +arguments can be given to limit updates to a subset of the hosts listed in the +.Ar distfile . +.It Fl n +Print the commands without executing them. This option is +useful for debugging +.Ar distfile . +.It Fl q +Quiet mode. Files that are being modified are normally +printed on standard output. The +.Fl q +option suppresses this. +.It Fl R +Remove extraneous files. If a directory is being updated, any files that exist +on the remote host that do not exist in the master directory are removed. +This is useful for maintaining truly identical copies of directories. +.It Fl v +Verify that the files are up to date on all the hosts. Any files +that are out of date will be displayed but no files will be changed +nor any mail sent. +.It Fl w +Whole mode. The whole file name is appended to the destination directory +name. Normally, only the last component of a name is used when renaming files. +This will preserve the directory structure of the files being +copied instead of flattening the directory structure. For example, +renaming a list of files such as ( dir1/f1 dir2/f2 ) to dir3 would create +files dir3/dir1/f1 and dir3/dir2/f2 instead of dir3/f1 and dir3/f2. +.It Fl y +Younger mode. Files are normally updated if their +.Ar mtime +and +.Ar size +(see +.Xr stat 2 ) +disagree. The +.Fl y +option causes +.Nm rdist +not to update files that are younger than the master copy. +This can be used +to prevent newer copies on other hosts from being replaced. +A warning message is printed for files which are newer than the master copy. +.El +.Pp +.Ar Distfile +contains a sequence of entries that specify the files +to be copied, the destination hosts, and what operations to perform +to do the updating. Each entry has one of the following formats. +.Pp +.Bd -literal -offset indent -compact + `=' +[label:] `\->' +[label:] `::' +.Ed +.Pp +The first format is used for defining variables. +The second format is used for distributing files to other hosts. +The third format is used for making lists of files that have been changed +since some given date. +The +.Ar source list +specifies a +list of files and/or directories on the local host which are to be used +as the master copy for distribution. +The +.Ar destination list +is the list of hosts to which these files are to be +copied. Each file in the source list is added to a list of changes +if the file is out of date on the host which is being updated (second format) or +the file is newer than the time stamp file (third format). +.Pp +Labels are optional. They are used to identify a command for partial updates. +.Pp +Newlines, tabs, and blanks are only used as separators and are +otherwise ignored. Comments begin with `#' and end with a newline. +.Pp +Variables to be expanded begin with `$' followed by one character or +a name enclosed in curly braces (see the examples at the end). +.Pp +The source and destination lists have the following format: +.Bd -literal -offset indent + +.Ed +or +.Bd -literal -offset indent -compact +`(' `)' +.Ed +.Pp +The shell meta-characters `[', `]', `{', `}', `*', and `?' +are recognized and expanded (on the local host only) in the same way as +.Xr csh 1 . +They can be escaped with a backslash. +The `~' character is also expanded in the same way as +.Xr csh 1 +but is expanded separately on the local and destination hosts. +When the +.Fl w +option is used with a file name that begins with `~', everything except the +home directory is appended to the destination name. +File names which do not begin with `/' or `~' use the destination user's +home directory as the root directory for the rest of the file name. +.Pp +The command list consists of zero or more commands of the following +format. +.Bd -ragged -offset indent -compact +.Bl -column except_patx pattern\ listx +.It `install' opt_dest_name `;' +.It `notify' `;' +.It `except' `;' +.It `except_pat' `;' +.It `special' string `;' +.El +.Ed +.Pp +The +.Ic install +command is used to copy out of date files and/or directories. +Each source file is copied to each host in the destination list. +Directories are recursively copied in the same way. +.Ar Opt_dest_name +is an optional parameter to rename files. +If no +.Ic install +command appears in the command list or +the destination name is not specified, +the source file name is used. +Directories in the path name will be created if they +do not exist on the remote host. +To help prevent disasters, a non-empty directory on a target host will +never be replaced with a regular file or a symbolic link. +However, under the `\-R' option a non-empty directory will be removed +if the corresponding filename is completely absent on the master host. +The +.Ar options +are `\-R', `\-h', `\-i', `\-v', `\-w', `\-y', and `\-b' +and have the same semantics as +options on the command line except they only apply to the files +in the source list. +The login name used on the destination host is the same as the local host +unless the destination name is of the format ``login@host". +.Pp +The +.Ic notify +command is used to mail the list of files updated (and any errors +that may have occurred) to the listed names. +If no `@' appears in the name, the destination host is appended to +the name +(e.g., name1@host, name2@host, ...). +.Pp +The +.Ic except +command is used to update all of the files in the source list +.Ic except +for the files listed in +.Ar name list . +This is usually used to copy everything in a directory except certain files. +.Pp +The +.Ic except_pat +command is like the +.Ic except +command except that +.Ar pattern list +is a list of regular expressions +(see +.Xr ed 1 +for details). +If one of the patterns matches some string within a file name, that file will +be ignored. +Note that since `\e' is a quote character, it must be doubled to become +part of the regular expression. Variables are expanded in +.Ar pattern list +but not shell file pattern matching characters. To include a `$', it +must be escaped with `\e'. +.Pp +The +.Ic special +command is used to specify +.Xr sh 1 +commands that are to be executed on the +remote host after the file in +.Ar name list +is updated or installed. +If the +.Ar name list +is omitted then the shell commands will be executed +for every file updated or installed. The shell variable `FILE' is set +to the current filename before executing the commands in +.Ar string . +.Ar String +starts and ends with `"' and can cross multiple lines in +.Ar distfile . +Multiple commands to the shell should be separated by `;'. +Commands are executed in the user's home directory on the host +being updated. +The +.Ar special +command can be used to rebuild private databases, etc. +after a program has been updated. +.Pp +The following is a small example: +.Bd -literal -offset indent +HOSTS = ( matisse root@arpa ) + +FILES = ( /bin /lib /usr/bin /usr/games +\t/usr/include/{*.h,{stand,sys,vax*,pascal,machine}/*.h} +\t/usr/lib /usr/man/man? /usr/ucb /usr/local/rdist ) + +EXLIB = ( Mail.rc aliases aliases.dir aliases.pag crontab dshrc +\tsendmail.cf sendmail.fc sendmail.hf sendmail.st uucp vfont ) + +${FILES} -> ${HOSTS} +\tinstall -R ; +\texcept /usr/lib/${EXLIB} ; +\texcept /usr/games/lib ; +\tspecial /usr/lib/sendmail "/usr/lib/sendmail -bz" ; + +srcs: +/usr/src/bin -> arpa +\texcept_pat ( \e\e.o\e$ /SCCS\e$ ) ; + +IMAGEN = (ips dviimp catdvi) + +imagen: +/usr/local/${IMAGEN} -> arpa +\tinstall /usr/local/lib ; +\tnotify ralph ; + +${FILES} :: stamp.cory +\tnotify root@cory ; +.Ed +.Sh FILES +.Bl -tag -width /tmp/rdist* -compact +.It Pa distfile +input command file +.It Pa /tmp/rdist* +temporary file for update lists +.El +.Sh SEE ALSO +.Xr sh 1 , +.Xr csh 1 , +.Xr stat 2 +.Sh HISTORY +The +.Nm rdist +command appeared in +.Bx 4.3 . +.Sh DIAGNOSTICS +A complaint about mismatch of rdist version numbers may really stem +from some problem with starting your shell, e.g., you are in too many groups. +.Sh BUGS +Source files must reside on the local host where +.Nm rdist +is executed. +.Pp +There is no easy way to have a special command executed after all files +in a directory have been updated. +.Pp +Variable expansion only works for name lists; there should be a general macro +facility. +.Pp +.Nm Rdist +aborts on files which have a negative mtime (before Jan 1, 1970). +.Pp +There should be a `force' option to allow replacement of non-empty directories +by regular files or symlinks. A means of updating file modes and owners +of otherwise identical files is also needed. diff --git a/usr.bin/rdist/server.c b/usr.bin/rdist/server.c new file mode 100644 index 0000000..aa33936 --- /dev/null +++ b/usr.bin/rdist/server.c @@ -0,0 +1,1584 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)server.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include "defs.h" + +#define ack() (void) write(rem, "\0\n", 2) +#define err() (void) write(rem, "\1\n", 2) + +struct linkbuf *ihead; /* list of files with more than one link */ +char buf[BUFSIZ]; /* general purpose buffer */ +char target[BUFSIZ]; /* target/source directory name */ +char *tp; /* pointer to end of target name */ +char *Tdest; /* pointer to last T dest*/ +int catname; /* cat name to target name */ +char *stp[32]; /* stack of saved tp's for directories */ +int oumask; /* old umask for creating files */ + +extern FILE *lfp; /* log file for mailing changes */ + +static int chkparent __P((char *)); +static void clean __P((char *)); +static void comment __P((char *)); +static void dospecial __P((char *)); +static int fchog __P((int, char *, char *, char *, int)); +static void hardlink __P((char *)); +static void note __P((const char *, ...)); +static void query __P((char *)); +static void recvf __P((char *, int)); +static void removeit __P((struct stat *)); +static int response __P((void)); +static void rmchk __P((int)); +static struct linkbuf * + savelink __P((struct stat *)); +static void sendf __P((char *, int)); +static int update __P((char *, int, struct stat *)); + +/* + * Server routine to read requests and process them. + * Commands are: + * Tname - Transmit file if out of date + * Vname - Verify if file out of date or not + * Qname - Query if file exists. Return mtime & size if it does. + */ +void +server() +{ + char cmdbuf[BUFSIZ]; + register char *cp; + + signal(SIGHUP, cleanup); + signal(SIGINT, cleanup); + signal(SIGQUIT, cleanup); + signal(SIGTERM, cleanup); + signal(SIGPIPE, cleanup); + + rem = 0; + oumask = umask(0); + (void) sprintf(buf, "V%d\n", VERSION); + (void) write(rem, buf, strlen(buf)); + + for (;;) { + cp = cmdbuf; + if (read(rem, cp, 1) <= 0) + return; + if (*cp++ == '\n') { + error("server: expected control record\n"); + continue; + } + do { + if (read(rem, cp, 1) != 1) + cleanup(0); + } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); + *--cp = '\0'; + cp = cmdbuf; + switch (*cp++) { + case 'T': /* init target file/directory name */ + catname = 1; /* target should be directory */ + goto dotarget; + + case 't': /* init target file/directory name */ + catname = 0; + dotarget: + if (exptilde(target, cp) == NULL) + continue; + tp = target; + while (*tp) + tp++; + ack(); + continue; + + case 'R': /* Transfer a regular file. */ + recvf(cp, S_IFREG); + continue; + + case 'D': /* Transfer a directory. */ + recvf(cp, S_IFDIR); + continue; + + case 'K': /* Transfer symbolic link. */ + recvf(cp, S_IFLNK); + continue; + + case 'k': /* Transfer hard link. */ + hardlink(cp); + continue; + + case 'E': /* End. (of directory) */ + *tp = '\0'; + if (catname <= 0) { + error("server: too many 'E's\n"); + continue; + } + tp = stp[--catname]; + *tp = '\0'; + ack(); + continue; + + case 'C': /* Clean. Cleanup a directory */ + clean(cp); + continue; + + case 'Q': /* Query. Does the file/directory exist? */ + query(cp); + continue; + + case 'S': /* Special. Execute commands */ + dospecial(cp); + continue; + +#ifdef notdef + /* + * These entries are reserved but not currently used. + * The intent is to allow remote hosts to have master copies. + * Currently, only the host rdist runs on can have masters. + */ + case 'X': /* start a new list of files to exclude */ + except = bp = NULL; + case 'x': /* add name to list of files to exclude */ + if (*cp == '\0') { + ack(); + continue; + } + if (*cp == '~') { + if (exptilde(buf, cp) == NULL) + continue; + cp = buf; + } + if (bp == NULL) + except = bp = expand(makeblock(NAME, cp), E_VARS); + else + bp->b_next = expand(makeblock(NAME, cp), E_VARS); + while (bp->b_next != NULL) + bp = bp->b_next; + ack(); + continue; + + case 'I': /* Install. Transfer file if out of date. */ + opts = 0; + while (*cp >= '0' && *cp <= '7') + opts = (opts << 3) | (*cp++ - '0'); + if (*cp++ != ' ') { + error("server: options not delimited\n"); + return; + } + install(cp, opts); + continue; + + case 'L': /* Log. save message in log file */ + log(lfp, cp); + continue; +#endif + + case '\1': + nerrs++; + continue; + + case '\2': + return; + + default: + error("server: unknown command '%s'\n", cp); + case '\0': + continue; + } + } +} + +/* + * Update the file(s) if they are different. + * destdir = 1 if destination should be a directory + * (i.e., more than one source is being copied to the same destination). + */ +void +install(src, dest, destdir, opts) + char *src, *dest; + int destdir, opts; +{ + char *rname; + char destcopy[BUFSIZ]; + + if (dest == NULL) { + opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ + dest = src; + } + + if (nflag || debug) { + printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", + opts & WHOLE ? " -w" : "", + opts & YOUNGER ? " -y" : "", + opts & COMPARE ? " -b" : "", + opts & REMOVE ? " -R" : "", src, dest); + if (nflag) + return; + } + + rname = exptilde(target, src); + if (rname == NULL) + return; + tp = target; + while (*tp) + tp++; + /* + * If we are renaming a directory and we want to preserve + * the directory heirarchy (-w), we must strip off the leading + * directory name and preserve the rest. + */ + if (opts & WHOLE) { + while (*rname == '/') + rname++; + destdir = 1; + } else { + rname = rindex(target, '/'); + if (rname == NULL) + rname = target; + else + rname++; + } + if (debug) + printf("target = %s, rname = %s\n", target, rname); + /* + * Pass the destination file/directory name to remote. + */ + (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) + return; + + if (destdir) { + strcpy(destcopy, dest); + Tdest = destcopy; + } + sendf(rname, opts); + Tdest = 0; +} + +#define protoname() (pw ? pw->pw_name : user) +#define protogroup() (gr ? gr->gr_name : group) +/* + * Transfer the file or directory in target[]. + * rname is the name of the file on the remote host. + */ +static void +sendf(rname, opts) + char *rname; + int opts; +{ + register struct subcmd *sc; + struct stat stb; + int sizerr, f, u, len; + off_t i; + DIR *d; + struct direct *dp; + char *otp, *cp; + extern struct subcmd *subcmds; + static char user[15], group[15]; + + if (debug) + printf("sendf(%s, %x)\n", rname, opts); + + if (except(target)) + return; + if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { + error("%s: %s\n", target, strerror(errno)); + return; + } + if ((u = update(rname, opts, &stb)) == 0) { + if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1) + (void) savelink(&stb); + return; + } + + if (pw == NULL || pw->pw_uid != stb.st_uid) + if ((pw = getpwuid(stb.st_uid)) == NULL) { + log(lfp, "%s: no password entry for uid %d \n", + target, stb.st_uid); + pw = NULL; + (void)sprintf(user, ":%lu", stb.st_uid); + } + if (gr == NULL || gr->gr_gid != stb.st_gid) + if ((gr = getgrgid(stb.st_gid)) == NULL) { + log(lfp, "%s: no name for group %d\n", + target, stb.st_gid); + gr = NULL; + (void)sprintf(group, ":%lu", stb.st_gid); + } + if (u == 1) { + if (opts & VERIFY) { + log(lfp, "need to install: %s\n", target); + goto dospecial; + } + log(lfp, "installing: %s\n", target); + opts &= ~(COMPARE|REMOVE); + } + + switch (stb.st_mode & S_IFMT) { + case S_IFDIR: + if ((d = opendir(target)) == NULL) { + error("%s: %s\n", target, strerror(errno)); + return; + } + (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts, + stb.st_mode & 07777, protoname(), protogroup(), rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) { + closedir(d); + return; + } + + if (opts & REMOVE) + rmchk(opts); + + otp = tp; + len = tp - target; + while (dp = readdir(d)) { + if (!strcmp(dp->d_name, ".") || + !strcmp(dp->d_name, "..")) + continue; + if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { + error("%s/%s: Name too long\n", target, + dp->d_name); + continue; + } + tp = otp; + *tp++ = '/'; + cp = dp->d_name; + while (*tp++ = *cp++) + ; + tp--; + sendf(dp->d_name, opts); + } + closedir(d); + (void) write(rem, "E\n", 2); + (void) response(); + tp = otp; + *tp = '\0'; + return; + + case S_IFLNK: + if (u != 1) + opts |= COMPARE; + if (stb.st_nlink > 1) { + struct linkbuf *lp; + + if ((lp = savelink(&stb)) != NULL) { + /* install link */ + if (*lp->target == 0) + (void) sprintf(buf, "k%o %s %s\n", opts, + lp->pathname, rname); + else + (void) sprintf(buf, "k%o %s/%s %s\n", opts, + lp->target, lp->pathname, rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + (void) response(); + return; + } + } + (void) sprintf(buf, "K%o %o %qd %ld %s %s %s\n", opts, + stb.st_mode & 07777, stb.st_size, stb.st_mtime, + protoname(), protogroup(), rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) + return; + sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); + (void) write(rem, buf, stb.st_size); + if (debug) + printf("readlink = %.*s\n", (int)stb.st_size, buf); + goto done; + + case S_IFREG: + break; + + default: + error("%s: not a file or directory\n", target); + return; + } + + if (u == 2) { + if (opts & VERIFY) { + log(lfp, "need to update: %s\n", target); + goto dospecial; + } + log(lfp, "updating: %s\n", target); + } + + if (stb.st_nlink > 1) { + struct linkbuf *lp; + + if ((lp = savelink(&stb)) != NULL) { + /* install link */ + if (*lp->target == 0) + (void) sprintf(buf, "k%o %s %s\n", opts, + lp->pathname, rname); + else + (void) sprintf(buf, "k%o %s/%s %s\n", opts, + lp->target, lp->pathname, rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + (void) response(); + return; + } + } + + if ((f = open(target, O_RDONLY, 0)) < 0) { + error("%s: %s\n", target, strerror(errno)); + return; + } + (void) sprintf(buf, "R%o %o %qd %ld %s %s %s\n", opts, + stb.st_mode & 07777, stb.st_size, stb.st_mtime, + protoname(), protogroup(), rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) { + (void) close(f); + return; + } + sizerr = 0; + for (i = 0; i < stb.st_size; i += BUFSIZ) { + int amt = BUFSIZ; + if (i + amt > stb.st_size) + amt = stb.st_size - i; + if (sizerr == 0 && read(f, buf, amt) != amt) + sizerr = 1; + (void) write(rem, buf, amt); + } + (void) close(f); +done: + if (sizerr) { + error("%s: file changed size\n", target); + err(); + } else + ack(); + f = response(); + if (f < 0 || f == 0 && (opts & COMPARE)) + return; +dospecial: + for (sc = subcmds; sc != NULL; sc = sc->sc_next) { + if (sc->sc_type != SPECIAL) + continue; + if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) + continue; + log(lfp, "special \"%s\"\n", sc->sc_name); + if (opts & VERIFY) + continue; + (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + while (response() > 0) + ; + } +} + +static struct linkbuf * +savelink(stp) + struct stat *stp; +{ + struct linkbuf *lp; + + for (lp = ihead; lp != NULL; lp = lp->nextp) + if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) { + lp->count--; + return(lp); + } + lp = (struct linkbuf *) malloc(sizeof(*lp)); + if (lp == NULL) + log(lfp, "out of memory, link information lost\n"); + else { + lp->nextp = ihead; + ihead = lp; + lp->inum = stp->st_ino; + lp->devnum = stp->st_dev; + lp->count = stp->st_nlink - 1; + strcpy(lp->pathname, target); + if (Tdest) + strcpy(lp->target, Tdest); + else + *lp->target = 0; + } + return(NULL); +} + +/* + * Check to see if file needs to be updated on the remote machine. + * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date + * and 3 if comparing binaries to determine if out of date. + */ +static int +update(rname, opts, stp) + char *rname; + int opts; + struct stat *stp; +{ + register char *cp, *s; + register off_t size; + register time_t mtime; + + if (debug) + printf("update(%s, %x, %x)\n", rname, opts, stp); + + /* + * Check to see if the file exists on the remote machine. + */ + (void) sprintf(buf, "Q%s\n", rname); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); +again: + cp = s = buf; + do { + if (read(rem, cp, 1) != 1) + lostconn(0); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + + switch (*s++) { + case 'Y': + break; + + case 'N': /* file doesn't exist so install it */ + return(1); + + case '\1': + nerrs++; + if (*s != '\n') { + if (!iamremote) { + fflush(stdout); + (void) write(2, s, cp - s); + } + if (lfp != NULL) + (void) fwrite(s, 1, cp - s, lfp); + } + return(0); + + case '\3': + *--cp = '\0'; + if (lfp != NULL) + log(lfp, "update: note: %s\n", s); + goto again; + + default: + *--cp = '\0'; + error("update: unexpected response '%s'\n", s); + return(0); + } + + if (*s == '\n') + return(2); + + if (opts & COMPARE) + return(3); + + size = 0; + while (isdigit(*s)) + size = size * 10 + (*s++ - '0'); + if (*s++ != ' ') { + error("update: size not delimited\n"); + return(0); + } + mtime = 0; + while (isdigit(*s)) + mtime = mtime * 10 + (*s++ - '0'); + if (*s != '\n') { + error("update: mtime not delimited\n"); + return(0); + } + /* + * File needs to be updated? + */ + if (opts & YOUNGER) { + if (stp->st_mtime == mtime) + return(0); + if (stp->st_mtime < mtime) { + log(lfp, "Warning: %s: remote copy is newer\n", target); + return(0); + } + } else if (stp->st_mtime == mtime && stp->st_size == size) + return(0); + return(2); +} + +/* + * Query. Check to see if file exists. Return one of the following: + * N\n - doesn't exist + * Ysize mtime\n - exists and its a regular file (size & mtime of file) + * Y\n - exists and its a directory or symbolic link + * ^Aerror message\n + */ +static void +query(name) + char *name; +{ + struct stat stb; + + if (catname) + (void) sprintf(tp, "/%s", name); + + if (lstat(target, &stb) < 0) { + if (errno == ENOENT) + (void) write(rem, "N\n", 2); + else + error("%s:%s: %s\n", host, target, strerror(errno)); + *tp = '\0'; + return; + } + + switch (stb.st_mode & S_IFMT) { + case S_IFREG: + (void) sprintf(buf, "Y%qd %ld\n", stb.st_size, stb.st_mtime); + (void) write(rem, buf, strlen(buf)); + break; + + case S_IFLNK: + case S_IFDIR: + (void) write(rem, "Y\n", 2); + break; + + default: + error("%s: not a file or directory\n", name); + break; + } + *tp = '\0'; +} + +static void +recvf(cmd, type) + char *cmd; + int type; +{ + register char *cp; + int f, mode, opts, wrerr, olderrno; + off_t i, size; + time_t mtime; + struct stat stb; + struct timeval tvp[2]; + char *owner, *group; + char new[BUFSIZ]; + extern char *tempname; + + cp = cmd; + opts = 0; + while (*cp >= '0' && *cp <= '7') + opts = (opts << 3) | (*cp++ - '0'); + if (*cp++ != ' ') { + error("recvf: options not delimited\n"); + return; + } + mode = 0; + while (*cp >= '0' && *cp <= '7') + mode = (mode << 3) | (*cp++ - '0'); + if (*cp++ != ' ') { + error("recvf: mode not delimited\n"); + return; + } + size = 0; + while (isdigit(*cp)) + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') { + error("recvf: size not delimited\n"); + return; + } + mtime = 0; + while (isdigit(*cp)) + mtime = mtime * 10 + (*cp++ - '0'); + if (*cp++ != ' ') { + error("recvf: mtime not delimited\n"); + return; + } + owner = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp != ' ') { + error("recvf: owner name not delimited\n"); + return; + } + *cp++ = '\0'; + group = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp != ' ') { + error("recvf: group name not delimited\n"); + return; + } + *cp++ = '\0'; + + if (type == S_IFDIR) { + if (catname >= sizeof(stp)) { + error("%s:%s: too many directory levels\n", + host, target); + return; + } + stp[catname] = tp; + if (catname++) { + *tp++ = '/'; + while (*tp++ = *cp++) + ; + tp--; + } + if (opts & VERIFY) { + ack(); + return; + } + if (lstat(target, &stb) == 0) { + if (ISDIR(stb.st_mode)) { + if ((stb.st_mode & 07777) == mode) { + ack(); + return; + } + buf[0] = '\0'; + (void) sprintf(buf + 1, + "%s: Warning: remote mode %o != local mode %o\n", + target, stb.st_mode & 07777, mode); + (void) write(rem, buf, strlen(buf + 1) + 1); + return; + } + errno = ENOTDIR; + } else if (errno == ENOENT && (mkdir(target, mode) == 0 || + chkparent(target) == 0 && mkdir(target, mode) == 0)) { + if (fchog(-1, target, owner, group, mode) == 0) + ack(); + return; + } + error("%s:%s: %s\n", host, target, strerror(errno)); + tp = stp[--catname]; + *tp = '\0'; + return; + } + + if (catname) + (void) sprintf(tp, "/%s", cp); + cp = rindex(target, '/'); + if (cp == NULL) + strcpy(new, tempname); + else if (cp == target) + (void) sprintf(new, "/%s", tempname); + else { + *cp = '\0'; + (void) sprintf(new, "%s/%s", target, tempname); + *cp = '/'; + } + + if (type == S_IFLNK) { + int j; + + ack(); + cp = buf; + for (i = 0; i < size; i += j) { + if ((j = read(rem, cp, size - i)) <= 0) + cleanup(0); + cp += j; + } + *cp = '\0'; + if (response() < 0) { + err(); + return; + } + if (symlink(buf, new) < 0) { + if (errno != ENOENT || chkparent(new) < 0 || + symlink(buf, new) < 0) + goto badnew1; + } + mode &= 0777; + if (opts & COMPARE) { + char tbuf[BUFSIZ]; + + if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 && + i == size && strncmp(buf, tbuf, size) == 0) { + (void) unlink(new); + ack(); + return; + } + if (opts & VERIFY) + goto differ; + } + goto fixup; + } + + if ((f = creat(new, mode)) < 0) { + if (errno != ENOENT || chkparent(new) < 0 || + (f = creat(new, mode)) < 0) + goto badnew1; + } + + ack(); + wrerr = 0; + for (i = 0; i < size; i += BUFSIZ) { + int amt = BUFSIZ; + + cp = buf; + if (i + amt > size) + amt = size - i; + do { + int j = read(rem, cp, amt); + + if (j <= 0) { + (void) close(f); + (void) unlink(new); + cleanup(0); + } + amt -= j; + cp += j; + } while (amt > 0); + amt = BUFSIZ; + if (i + amt > size) + amt = size - i; + if (wrerr == 0 && write(f, buf, amt) != amt) { + olderrno = errno; + wrerr++; + } + } + if (response() < 0) { + err(); + goto badnew2; + } + if (wrerr) + goto badnew1; + if (opts & COMPARE) { + FILE *f1, *f2; + int c; + + if ((f1 = fopen(target, "r")) == NULL) + goto badtarget; + if ((f2 = fopen(new, "r")) == NULL) { +badnew1: error("%s:%s: %s\n", host, new, strerror(errno)); + goto badnew2; + } + while ((c = getc(f1)) == getc(f2)) + if (c == EOF) { + (void) fclose(f1); + (void) fclose(f2); + ack(); + goto badnew2; + } + (void) fclose(f1); + (void) fclose(f2); + if (opts & VERIFY) { +differ: buf[0] = '\0'; + (void) sprintf(buf + 1, "need to update: %s\n",target); + (void) write(rem, buf, strlen(buf + 1) + 1); + goto badnew2; + } + } + + /* + * Set last modified time + */ + tvp[0].tv_sec = time(0); + tvp[0].tv_usec = 0; + tvp[1].tv_sec = mtime; + tvp[1].tv_usec = 0; + if (utimes(new, tvp) < 0) + note("%s: utimes failed %s: %s\n", host, new, strerror(errno)); + + if (fchog(f, new, owner, group, mode) < 0) { +badnew2: (void) close(f); + (void) unlink(new); + return; + } + (void) close(f); + +fixup: if (rename(new, target) < 0) { +badtarget: error("%s:%s: %s\n", host, target, strerror(errno)); + (void) unlink(new); + return; + } + + if (opts & COMPARE) { + buf[0] = '\0'; + (void) sprintf(buf + 1, "updated %s\n", target); + (void) write(rem, buf, strlen(buf + 1) + 1); + } else + ack(); +} + +/* + * Creat a hard link to existing file. + */ +static void +hardlink(cmd) + char *cmd; +{ + register char *cp; + struct stat stb; + char *oldname; + int opts, exists = 0; + + cp = cmd; + opts = 0; + while (*cp >= '0' && *cp <= '7') + opts = (opts << 3) | (*cp++ - '0'); + if (*cp++ != ' ') { + error("hardlink: options not delimited\n"); + return; + } + oldname = cp; + while (*cp && *cp != ' ') + cp++; + if (*cp != ' ') { + error("hardlink: oldname name not delimited\n"); + return; + } + *cp++ = '\0'; + + if (catname) { + (void) sprintf(tp, "/%s", cp); + } + if (lstat(target, &stb) == 0) { + int mode = stb.st_mode & S_IFMT; + if (mode != S_IFREG && mode != S_IFLNK) { + error("%s:%s: not a regular file\n", host, target); + return; + } + exists = 1; + } + if (chkparent(target) < 0 ) { + error("%s:%s: %s (no parent)\n", + host, target, strerror(errno)); + return; + } + if (exists && (unlink(target) < 0)) { + error("%s:%s: %s (unlink)\n", + host, target, strerror(errno)); + return; + } + if (link(oldname, target) < 0) { + error("%s:can't link %s to %s\n", + host, target, oldname); + return; + } + ack(); +} + +/* + * Check to see if parent directory exists and create one if not. + */ +static int +chkparent(name) + char *name; +{ + register char *cp; + struct stat stb; + + cp = rindex(name, '/'); + if (cp == NULL || cp == name) + return(0); + *cp = '\0'; + if (lstat(name, &stb) < 0) { + if (errno == ENOENT && chkparent(name) >= 0 && + mkdir(name, 0777 & ~oumask) >= 0) { + *cp = '/'; + return(0); + } + } else if (ISDIR(stb.st_mode)) { + *cp = '/'; + return(0); + } + *cp = '/'; + return(-1); +} + +/* + * Change owner, group and mode of file. + */ +static int +fchog(fd, file, owner, group, mode) + int fd; + char *file, *owner, *group; + int mode; +{ + register int i; + int uid, gid; + extern char user[]; + extern int userid; + + uid = userid; + if (userid == 0) { + if (*owner == ':') { + uid = atoi(owner + 1); + } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { + if ((pw = getpwnam(owner)) == NULL) { + if (mode & 04000) { + note("%s:%s: unknown login name, clearing setuid", + host, owner); + mode &= ~04000; + uid = 0; + } + } else + uid = pw->pw_uid; + } else + uid = pw->pw_uid; + if (*group == ':') { + gid = atoi(group + 1); + goto ok; + } + } else if ((mode & 04000) && strcmp(user, owner) != 0) + mode &= ~04000; + gid = -1; + if (gr == NULL || strcmp(group, gr->gr_name) != 0) { + if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL)) + || ((gr = getgrnam(group)) == NULL)) { + if (mode & 02000) { + note("%s:%s: unknown group", host, group); + mode &= ~02000; + } + } else + gid = gr->gr_gid; + } else + gid = gr->gr_gid; + if (userid && gid >= 0) { + if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++) + if (!(strcmp(user, gr->gr_mem[i]))) + goto ok; + mode &= ~02000; + gid = -1; + } +ok: if (fd != -1 && fchown(fd, uid, gid) < 0 || chown(file, uid, gid) < 0) + note("%s: %s chown: %s", host, file, strerror(errno)); + else if (mode & 07000 && + (fd != -1 && fchmod(fd, mode) < 0 || chmod(file, mode) < 0)) + note("%s: %s chmod: %s", host, file, strerror(errno)); + return(0); +} + +/* + * Check for files on the machine being updated that are not on the master + * machine and remove them. + */ +static void +rmchk(opts) + int opts; +{ + register char *cp, *s; + struct stat stb; + + if (debug) + printf("rmchk()\n"); + + /* + * Tell the remote to clean the files from the last directory sent. + */ + (void) sprintf(buf, "C%o\n", opts & VERIFY); + if (debug) + printf("buf = %s", buf); + (void) write(rem, buf, strlen(buf)); + if (response() < 0) + return; + for (;;) { + cp = s = buf; + do { + if (read(rem, cp, 1) != 1) + lostconn(0); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + + switch (*s++) { + case 'Q': /* Query if file should be removed */ + /* + * Return the following codes to remove query. + * N\n -- file exists - DON'T remove. + * Y\n -- file doesn't exist - REMOVE. + */ + *--cp = '\0'; + (void) sprintf(tp, "/%s", s); + if (debug) + printf("check %s\n", target); + if (except(target)) + (void) write(rem, "N\n", 2); + else if (lstat(target, &stb) < 0) + (void) write(rem, "Y\n", 2); + else + (void) write(rem, "N\n", 2); + break; + + case '\0': + *--cp = '\0'; + if (*s != '\0') + log(lfp, "%s\n", s); + break; + + case 'E': + *tp = '\0'; + ack(); + return; + + case '\1': + case '\2': + nerrs++; + if (*s != '\n') { + if (!iamremote) { + fflush(stdout); + (void) write(2, s, cp - s); + } + if (lfp != NULL) + (void) fwrite(s, 1, cp - s, lfp); + } + if (buf[0] == '\2') + lostconn(0); + break; + + default: + error("rmchk: unexpected response '%s'\n", buf); + err(); + } + } +} + +/* + * Check the current directory (initialized by the 'T' command to server()) + * for extraneous files and remove them. + */ +static void +clean(cp) + register char *cp; +{ + DIR *d; + register struct direct *dp; + struct stat stb; + char *otp; + int len, opts; + + opts = 0; + while (*cp >= '0' && *cp <= '7') + opts = (opts << 3) | (*cp++ - '0'); + if (*cp != '\0') { + error("clean: options not delimited\n"); + return; + } + if ((d = opendir(target)) == NULL) { + error("%s:%s: %s\n", host, target, strerror(errno)); + return; + } + ack(); + + otp = tp; + len = tp - target; + while (dp = readdir(d)) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { + error("%s:%s/%s: Name too long\n", + host, target, dp->d_name); + continue; + } + tp = otp; + *tp++ = '/'; + cp = dp->d_name;; + while (*tp++ = *cp++) + ; + tp--; + if (lstat(target, &stb) < 0) { + error("%s:%s: %s\n", host, target, strerror(errno)); + continue; + } + (void) sprintf(buf, "Q%s\n", dp->d_name); + (void) write(rem, buf, strlen(buf)); + cp = buf; + do { + if (read(rem, cp, 1) != 1) + cleanup(0); + } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); + *--cp = '\0'; + cp = buf; + if (*cp != 'Y') + continue; + if (opts & VERIFY) { + cp = buf; + *cp++ = '\0'; + (void) sprintf(cp, "need to remove: %s\n", target); + (void) write(rem, buf, strlen(cp) + 1); + } else + removeit(&stb); + } + closedir(d); + (void) write(rem, "E\n", 2); + (void) response(); + tp = otp; + *tp = '\0'; +} + +/* + * Remove a file or directory (recursively) and send back an acknowledge + * or an error message. + */ +static void +removeit(stp) + struct stat *stp; +{ + DIR *d; + struct direct *dp; + register char *cp; + struct stat stb; + char *otp; + int len; + + switch (stp->st_mode & S_IFMT) { + case S_IFREG: + case S_IFLNK: + if (unlink(target) < 0) + goto bad; + goto removed; + + case S_IFDIR: + break; + + default: + error("%s:%s: not a plain file\n", host, target); + return; + } + + if ((d = opendir(target)) == NULL) + goto bad; + + otp = tp; + len = tp - target; + while (dp = readdir(d)) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { + error("%s:%s/%s: Name too long\n", + host, target, dp->d_name); + continue; + } + tp = otp; + *tp++ = '/'; + cp = dp->d_name;; + while (*tp++ = *cp++) + ; + tp--; + if (lstat(target, &stb) < 0) { + error("%s:%s: %s\n", host, target, strerror(errno)); + continue; + } + removeit(&stb); + } + closedir(d); + tp = otp; + *tp = '\0'; + if (rmdir(target) < 0) { +bad: + error("%s:%s: %s\n", host, target, strerror(errno)); + return; + } +removed: + cp = buf; + *cp++ = '\0'; + (void) sprintf(cp, "removed %s\n", target); + (void) write(rem, buf, strlen(cp) + 1); +} + +/* + * Execute a shell command to handle special cases. + */ +static void +dospecial(cmd) + char *cmd; +{ + int fd[2], status, pid, i; + register char *cp, *s; + char sbuf[BUFSIZ]; + extern int userid, groupid; + + if (pipe(fd) < 0) { + error("%s\n", strerror(errno)); + return; + } + if ((pid = fork()) == 0) { + /* + * Return everything the shell commands print. + */ + (void) close(0); + (void) close(1); + (void) close(2); + (void) open(_PATH_DEVNULL, O_RDONLY); + (void) dup(fd[1]); + (void) dup(fd[1]); + (void) close(fd[0]); + (void) close(fd[1]); + setgid(groupid); + setuid(userid); + execl(_PATH_BSHELL, "sh", "-c", cmd, 0); + _exit(127); + } + (void) close(fd[1]); + s = sbuf; + *s++ = '\0'; + while ((i = read(fd[0], buf, sizeof(buf))) > 0) { + cp = buf; + do { + *s++ = *cp++; + if (cp[-1] != '\n') { + if (s < &sbuf[sizeof(sbuf)-1]) + continue; + *s++ = '\n'; + } + /* + * Throw away blank lines. + */ + if (s == &sbuf[2]) { + s--; + continue; + } + (void) write(rem, sbuf, s - sbuf); + s = &sbuf[1]; + } while (--i); + } + if (s > &sbuf[1]) { + *s++ = '\n'; + (void) write(rem, sbuf, s - sbuf); + } + while ((i = wait(&status)) != pid && i != -1) + ; + if (i == -1) + status = -1; + (void) close(fd[0]); + if (status) + error("shell returned %d\n", status); + else + ack(); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +log(FILE *fp, const char *fmt, ...) +#else +log(fp, fmt, va_alist) + FILE *fp; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + /* Print changes locally if not quiet mode */ + if (!qflag) + (void)vprintf(fmt, ap); + + /* Save changes (for mailing) if really updating files */ + if (!(options & VERIFY) && fp != NULL) + (void)vfprintf(fp, fmt, ap); + va_end(ap); +} + +void +#if __STDC__ +error(const char *fmt, ...) +#else +error(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + static FILE *fp; + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + ++nerrs; + if (!fp && !(fp = fdopen(rem, "w"))) + return; + if (iamremote) { + (void)fprintf(fp, "%crdist: ", 0x01); + (void)vfprintf(fp, fmt, ap); + fflush(fp); + } + else { + fflush(stdout); + (void)fprintf(stderr, "rdist: "); + (void)vfprintf(stderr, fmt, ap); + fflush(stderr); + } + if (lfp != NULL) { + (void)fprintf(lfp, "rdist: "); + (void)vfprintf(lfp, fmt, ap); + fflush(lfp); + } + va_end(ap); +} + +void +#if __STDC__ +fatal(const char *fmt, ...) +#else +fatal(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + static FILE *fp; + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + ++nerrs; + if (!fp && !(fp = fdopen(rem, "w"))) + return; + if (iamremote) { + (void)fprintf(fp, "%crdist: ", 0x02); + (void)vfprintf(fp, fmt, ap); + fflush(fp); + } + else { + fflush(stdout); + (void)fprintf(stderr, "rdist: "); + (void)vfprintf(stderr, fmt, ap); + fflush(stderr); + } + if (lfp != NULL) { + (void)fprintf(lfp, "rdist: "); + (void)vfprintf(lfp, fmt, ap); + fflush(lfp); + } + cleanup(0); +} + +static int +response() +{ + char *cp, *s; + char resp[BUFSIZ]; + + if (debug) + printf("response()\n"); + + cp = s = resp; + do { + if (read(rem, cp, 1) != 1) + lostconn(0); + } while (*cp++ != '\n' && cp < &resp[BUFSIZ]); + + switch (*s++) { + case '\0': + *--cp = '\0'; + if (*s != '\0') { + log(lfp, "%s\n", s); + return(1); + } + return(0); + case '\3': + *--cp = '\0'; + log(lfp, "Note: %s\n",s); + return(response()); + + default: + s--; + /* fall into... */ + case '\1': + case '\2': + nerrs++; + if (*s != '\n') { + if (!iamremote) { + fflush(stdout); + (void) write(2, s, cp - s); + } + if (lfp != NULL) + (void) fwrite(s, 1, cp - s, lfp); + } + if (resp[0] == '\2') + lostconn(0); + return(-1); + } +} + +/* + * Remove temporary files and do any cleanup operations before exiting. + */ +void +cleanup(signo) + int signo; +{ + (void) unlink(tempfile); + exit(1); +} + +static void +#if __STDC__ +note(const char *fmt, ...) +#else +note(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + static char buf[BUFSIZ]; + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + comment(buf); +} + +static void +comment(s) + char *s; +{ + char c; + + c = '\3'; + write(rem, &c, 1); + write(rem, s, strlen(s)); + c = '\n'; + write(rem, &c, 1); +} diff --git a/usr.bin/renice/Makefile b/usr.bin/renice/Makefile new file mode 100644 index 0000000..67cfd8f --- /dev/null +++ b/usr.bin/renice/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= renice + +.include diff --git a/usr.bin/renice/renice.8 b/usr.bin/renice/renice.8 new file mode 100644 index 0000000..5a260a8 --- /dev/null +++ b/usr.bin/renice/renice.8 @@ -0,0 +1,131 @@ +.\" Copyright (c) 1983, 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. +.\" +.\" @(#)renice.8 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt RENICE 8 +.Os BSD 4 +.Sh NAME +.Nm renice +.Nd alter priority of running processes +.Sh SYNOPSIS +.Nm renice +.Ar priority +.Oo +.Op Fl p +.Ar pid ... +.Oc +.Oo +.Op Fl g +.Ar pgrp ... +.Oc +.Oo +.Op Fl u +.Ar user ... +.Oc +.Sh DESCRIPTION +.Nm Renice +alters the +scheduling priority of one or more running processes. +The following +.Ar who +parameters are interpreted as process ID's, process group +ID's, or user names. +.Nm Renice Ns 'ing +a process group causes all processes in the process group +to have their scheduling priority altered. +.Nm Renice Ns 'ing +a user causes all processes owned by the user to have +their scheduling priority altered. +By default, the processes to be affected are specified by +their process ID's. +.Pp +Options supported by +.Nm renice : +.Bl -tag -width Ds +.It Fl g +Force +.Ar who +parameters to be interpreted as process group ID's. +.It Fl u +Force the +.Ar who +parameters to be interpreted as user names. +.It Fl p +Resets the +.Ar who +interpretation to be (the default) process ID's. +.El +.Pp +For example, +.Bd -literal -offset +renice +1 987 -u daemon root -p 32 +.Ed +.Pp +would change the priority of process ID's 987 and 32, and +all processes owned by users daemon and root. +.Pp +Users other than the super-user may only alter the priority of +processes they own, +and can only monotonically increase their ``nice value'' +within the range 0 to +.Dv PRIO_MAX +(20). +(This prevents overriding administrative fiats.) +The super-user +may alter the priority of any process +and set the priority to any value in the range +.Dv PRIO_MIN +(\-20) +to +.Dv PRIO_MAX . +Useful priorities are: +20 (the affected processes will run only when nothing else +in the system wants to), +0 (the ``base'' scheduling priority), +anything negative (to make things go very fast). +.Sh FILES +.Bl -tag -width /etc/passwd -compact +.It Pa /etc/passwd +to map user names to user ID's +.El +.Sh SEE ALSO +.Xr getpriority 2 , +.Xr setpriority 2 +.Sh BUGS +Non super-users can not increase scheduling priorities of their own processes, +even if they were the ones that decreased the priorities in the first place. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/renice/renice.c b/usr.bin/renice/renice.c new file mode 100644 index 0000000..6deba6b --- /dev/null +++ b/usr.bin/renice/renice.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1983, 1989, 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 copyright[] = +"@(#) Copyright (c) 1983, 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include + +/* + * Change the priority (nice) of processes + * or groups of processes which are already + * running. + */ +main(argc, argv) + char **argv; +{ + int which = PRIO_PROCESS; + int who = 0, prio, errs = 0; + + argc--, argv++; + if (argc < 2) { + fprintf(stderr, "usage: renice priority [ [ -p ] pids ] "); + fprintf(stderr, "[ [ -g ] pgrps ] [ [ -u ] users ]\n"); + exit(1); + } + prio = atoi(*argv); + argc--, argv++; + if (prio > PRIO_MAX) + prio = PRIO_MAX; + if (prio < PRIO_MIN) + prio = PRIO_MIN; + for (; argc > 0; argc--, argv++) { + if (strcmp(*argv, "-g") == 0) { + which = PRIO_PGRP; + continue; + } + if (strcmp(*argv, "-u") == 0) { + which = PRIO_USER; + continue; + } + if (strcmp(*argv, "-p") == 0) { + which = PRIO_PROCESS; + continue; + } + if (which == PRIO_USER) { + register struct passwd *pwd = getpwnam(*argv); + + if (pwd == NULL) { + fprintf(stderr, "renice: %s: unknown user\n", + *argv); + continue; + } + who = pwd->pw_uid; + } else { + who = atoi(*argv); + if (who < 0) { + fprintf(stderr, "renice: %s: bad value\n", + *argv); + continue; + } + } + errs += donice(which, who, prio); + } + exit(errs != 0); +} + +donice(which, who, prio) + int which, who, prio; +{ + int oldprio; + extern int errno; + + errno = 0, oldprio = getpriority(which, who); + if (oldprio == -1 && errno) { + fprintf(stderr, "renice: %d: ", who); + perror("getpriority"); + return (1); + } + if (setpriority(which, who, prio) < 0) { + fprintf(stderr, "renice: %d: ", who); + perror("setpriority"); + return (1); + } + printf("%d: old priority %d, new priority %d\n", who, oldprio, prio); + return (0); +} diff --git a/usr.bin/rev/Makefile b/usr.bin/rev/Makefile new file mode 100644 index 0000000..1952ce9 --- /dev/null +++ b/usr.bin/rev/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= rev + +.include diff --git a/usr.bin/rev/rev.1 b/usr.bin/rev/rev.1 new file mode 100644 index 0000000..7c50efc --- /dev/null +++ b/usr.bin/rev/rev.1 @@ -0,0 +1,48 @@ +.\" Copyright (c) 1985, 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. +.\" +.\" @(#)rev.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt REV 1 +.Os +.Sh NAME +.Nm rev +.Nd reverse lines of a file +.Sh SYNOPSIS +.Nm rev +.Op Ar file +.Sh DESCRIPTION +The +.Nm rev +utility copies the specified files to the standard output, reversing the +order of characters in every line. +If no files are specified, the standard input is read. diff --git a/usr.bin/rev/rev.c b/usr.bin/rev/rev.c new file mode 100644 index 0000000..fe95991 --- /dev/null +++ b/usr.bin/rev/rev.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rev.c 8.2 (Berkeley) 1/2/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char *filename, *p, *t; + FILE *fp; + size_t len; + int ch, rval; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + fp = stdin; + filename = "stdin"; + rval = 0; + do { + if (*argv) { + if ((fp = fopen(*argv, "r")) == NULL) { + warn("%s", *argv); + rval = 1; + ++argv; + continue; + } + filename = *argv++; + } + while ((p = fgetln(fp, &len)) != NULL) { + if (p[len - 1] == '\n') + --len; + t = p + len - 1; + for (t = p + len - 1; t >= p; --t) + putchar(*t); + putchar('\n'); + } + if (ferror(fp)) { + warn("%s", filename); + rval = 1; + } + (void)fclose(fp); + } while(*argv); + exit(rval); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: rev [file ...]\n"); + exit(1); +} diff --git a/usr.bin/rlogin/Makefile b/usr.bin/rlogin/Makefile new file mode 100644 index 0000000..72a77b4 --- /dev/null +++ b/usr.bin/rlogin/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 7/19/93 + +PROG= rlogin +SRCS= rlogin.c krcmd.c kcmd.c des_rw.c +DPADD= ${LIBKRB} ${LIBDES} +CFLAGS+=-DKERBEROS -DCRYPT +LDADD= -lkrb -ldes +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg + +.include diff --git a/usr.bin/rlogin/des_rw.c b/usr.bin/rlogin/des_rw.c new file mode 100644 index 0000000..dbe47f0 --- /dev/null +++ b/usr.bin/rlogin/des_rw.c @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 1989, 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[] = "@(#)des_rw.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#ifdef CRYPT +#ifdef KERBEROS +#include + +#include +#include + +#include +#include +#include +#include + +static unsigned char des_inbuf[10240], storage[10240], *store_ptr; +static bit_64 *key; +static u_char *key_schedule; + +/* XXX these should be in a kerberos include file */ +int krb_net_read __P((int, char *, int)); +#ifdef notdef +/* XXX too hard to make this work */ +int des_pcbc_encrypt __P((des_cblock *, des_cblock *, long, + des_key_schedule, des_cblock *, int)); +#endif + +/* + * NB: These routines will not function properly if NBIO + * is set + */ + +/* + * des_set_key + * + * Set des encryption/decryption key for use by the des_read and + * des_write routines + * + * The inkey parameter is actually the DES initial vector, + * and the insched is the DES Key unwrapped for faster decryption + */ + +void +des_set_key(inkey, insched) + bit_64 *inkey; + u_char *insched; +{ + key = inkey; + key_schedule = insched; +} + +void +des_clear_key() +{ + bzero((char *) key, sizeof(C_Block)); + bzero((char *) key_schedule, sizeof(Key_schedule)); +} + + +int +des_read(fd, buf, len) + int fd; + register char *buf; + int len; +{ + int nreturned = 0; + long net_len, rd_len; + int nstored = 0; + + if (nstored >= len) { + (void) bcopy(store_ptr, buf, len); + store_ptr += len; + nstored -= len; + return(len); + } else if (nstored) { + (void) bcopy(store_ptr, buf, nstored); + nreturned += nstored; + buf += nstored; + len -= nstored; + nstored = 0; + } + + if (krb_net_read(fd, (char *)&net_len, sizeof(net_len)) != + sizeof(net_len)) { + /* XXX can't read enough, pipe + must have closed */ + return(0); + } + net_len = ntohl(net_len); + if (net_len <= 0 || net_len > sizeof(des_inbuf)) { + /* preposterous length; assume out-of-sync; only + recourse is to close connection, so return 0 */ + return(0); + } + /* the writer tells us how much real data we are getting, but + we need to read the pad bytes (8-byte boundary) */ + rd_len = roundup(net_len, 8); + if (krb_net_read(fd, (char *)des_inbuf, rd_len) != rd_len) { + /* pipe must have closed, return 0 */ + return(0); + } + (void) des_pcbc_encrypt(des_inbuf, /* inbuf */ + storage, /* outbuf */ + net_len, /* length */ + key_schedule, /* DES key */ + key, /* IV */ + DECRYPT); /* direction */ + + if(net_len < 8) + store_ptr = storage + 8 - net_len; + else + store_ptr = storage; + + nstored = net_len; + if (nstored > len) { + (void) bcopy(store_ptr, buf, len); + nreturned += len; + store_ptr += len; + nstored -= len; + } else { + (void) bcopy(store_ptr, buf, nstored); + nreturned += nstored; + nstored = 0; + } + + return(nreturned); +} + +static unsigned char des_outbuf[10240]; /* > longest write */ + +int +des_write(fd, buf, len) + int fd; + char *buf; + int len; +{ + static int seeded = 0; + static char garbage_buf[8]; + long net_len, garbage; + + if(len < 8) { + if(!seeded) { + seeded = 1; + srandom((int) time((long *)0)); + } + garbage = random(); + /* insert random garbage */ + (void) bcopy(&garbage, garbage_buf, MIN(sizeof(long),8)); + /* this "right-justifies" the data in the buffer */ + (void) bcopy(buf, garbage_buf + 8 - len, len); + } + /* pcbc_encrypt outputs in 8-byte (64 bit) increments */ + + (void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf, + des_outbuf, + (len < 8) ? 8 : len, + key_schedule, /* DES key */ + key, /* IV */ + ENCRYPT); + + /* tell the other end the real amount, but send an 8-byte padded + packet */ + net_len = htonl(len); + (void) write(fd, &net_len, sizeof(net_len)); + (void) write(fd, des_outbuf, roundup(len,8)); + return(len); +} +#endif /* KERBEROS */ +#endif /* CRYPT */ diff --git a/usr.bin/rlogin/kcmd.c b/usr.bin/rlogin/kcmd.c new file mode 100644 index 0000000..3f6a138 --- /dev/null +++ b/usr.bin/rlogin/kcmd.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1983, 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 Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; +static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "krb.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define START_PORT 5120 /* arbitrary */ + +int getport __P((int *)); + +int +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 + struct hostent *hp; + int rc; + char *host_save; + int status; + + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == NULL) { + /* 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; + +#ifdef KERBEROS + /* If realm is null, look up from table */ + if (realm == NULL || realm[0] == '\0') + realm = krb_realmofhost(host_save); +#endif /* KERBEROS */ + + 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 + 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(NULL); + 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"); + status = -1; + 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; + } + } +#ifdef KERBEROS + if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, + realm, (unsigned long) getpid(), msg_data, + cred, schedule, + laddr, + faddr, + "KCMDV0.1")) != KSUCCESS) + goto bad2; +#endif /* KERBEROS */ + + (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); +} + +int +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 + (void) close(s); + errno = EAGAIN; /* close */ + return (-1); + } + } +} diff --git a/usr.bin/rlogin/krb.h b/usr.bin/rlogin/krb.h new file mode 100644 index 0000000..469af1c --- /dev/null +++ b/usr.bin/rlogin/krb.h @@ -0,0 +1,51 @@ +/*- + * 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. + * + * @(#)krb.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * XXX + * These should be in a kerberos include file. + */ +void des_clear_key __P(()); +int des_read __P((int, char *, int)); +void des_set_key __P((C_Block, Key_schedule)); +int des_write __P((int, char *, int)); +int krb_net_read __P((int, char *, int)); +char *krb_realmofhost __P((char *)); +int krb_sendauth __P((long, int, KTEXT, char *, char *, char *, + u_long, MSG_DAT *, CREDENTIALS *, Key_schedule, + struct sockaddr_in *, struct sockaddr_in *, char *)); +int krcmd __P((char **, u_short, char *, char *, int *, char *)); +int krcmd_mutual __P((char **, u_short, char *, char *, int *, + char *, CREDENTIALS *, Key_schedule)); diff --git a/usr.bin/rlogin/krcmd.c b/usr.bin/rlogin/krcmd.c new file mode 100644 index 0000000..ee06d6a --- /dev/null +++ b/usr.bin/rlogin/krcmd.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)krcmd.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * $Source: /usr/src/usr.bin/rlogin/RCS/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 +#ifdef CRYPT +#include +#endif + +#include + +#include +#include + +#include + +#define SERVICE_NAME "rcmd" + +int kcmd __P((int *, char **, u_short, char *, char *, char *, int *, + KTEXT, char *, char *, CREDENTIALS *, Key_schedule, MSG_DAT *, + struct sockaddr_in *, struct sockaddr_in *, long)); + +/* + * 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 +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/rlogin/rlogin.1 b/usr.bin/rlogin/rlogin.1 new file mode 100644 index 0000000..60da3cc --- /dev/null +++ b/usr.bin/rlogin/rlogin.1 @@ -0,0 +1,183 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rlogin.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt RLOGIN 1 +.Os BSD 4.2 +.Sh NAME +.Nm rlogin +.Nd remote login +.Sh SYNOPSIS +.Ar rlogin +.Op Fl 8EKLdx +.Op Fl e Ar char +.Op Fl k Ar realm +.Op Fl l Ar username +.Ar host +.Sh DESCRIPTION +.Nm Rlogin +starts a terminal session on a remote host +.Ar host . +.Pp +.Nm Rlogin +first attempts to use the Kerberos authorization mechanism, described below. +If the remote host does not supporting Kerberos the standard Berkeley +.Pa rhosts +authorization mechanism is used. +The options are as follows: +.Bl -tag -width flag +.It Fl 8 +The +.Fl 8 +option allows an eight-bit input data path at all times; otherwise +parity bits are stripped except when the remote side's stop and start +characters are other than +^S/^Q . +.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 rlogin session to be run in ``litout'' (see +.Xr tty 4 ) +mode. +.It Fl d +The +.Fl d +option turns on socket debugging (see +.Xr setsockopt 2 ) +on the TCP sockets used for communication with the remote host. +.It Fl e +The +.Fl e +option allows user specification of the escape character, which is +``~'' by default. +This specification may be as a literal character, or as an octal +value in the form \ennn. +.It Fl k +The +.FL k +option requests rlogin to obtain tickets for the remote host +in realm +.Ar realm +instead of the remote host's realm as determined by +.Xr krb_realmofhost 3 . +.It Fl x +The +.Fl x +option turns on +.Tn DES +encryption for all data passed via the +rlogin session. +This may impact response time and +.Tn CPU +utilization, but provides +increased security. +.El +.Pp +A line of the form ``.'' disconnects from the remote host. +Similarly, the line ``^Z'' will suspend the +.Nm rlogin +session, and ``'' suspends the +send portion of the rlogin, but allows output from the remote system. +By default, the tilde (``~'') character is the escape character, and +normally control-Y (``^Y'') is the delayed-suspend character. +.Pp +All echoing takes place at the remote site, so that (except for delays) +the +.Nm rlogin +is transparent. +Flow control via ^S/^Q and flushing of input and output on interrupts +are handled properly. +.Sh KERBEROS AUTHENTICATION +Each user may have a private authorization list in the file +.Pa .klogin +in their home directory. +Each line in this file should contain a Kerberos principal name of the +form +.Ar principal.instance@realm . +If the originating user is authenticated to one of the principals named +in +.Pa .klogin , +access is granted to the account. +The principal +.Ar accountname.@localrealm +is granted access if +there is no +.Pa .klogin +file. +Otherwise a login and password will be prompted for on the remote machine +as in +.Xr login 1 . +To avoid certain security problems, the +.Pa .klogin +file must be owned by +the remote user. +.Pp +If Kerberos authentication fails, a warning message is printed and the +standard Berkeley +.Nm rlogin +is used instead. +.Sh ENVIRONMENT +The following environment variable is utilized by +.Nm rlogin : +.Bl -tag -width TERM +.It Ev TERM +Determines the user's terminal type. +.El +.Sh SEE ALSO +.Xr rsh 1 , +.Xr kerberos 3 , +.Xr krb_sendauth 3 , +.Xr krb_realmofhost 3 +.Sh HISTORY +The +.Nm rlogin +command appeared in +.Bx 4.2 . +.Sh BUGS +.Nm Rlogin +will be replaced by +.Xr telnet 1 +in the near future. +.Pp +More of the environment should be propagated. diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c new file mode 100644 index 0000000..5439c48 --- /dev/null +++ b/usr.bin/rlogin/rlogin.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 1983, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1983, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * rlogin - remote login + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +#ifdef KERBEROS +#include +#include + +#include "krb.h" + +CREDENTIALS cred; +Key_schedule schedule; +int use_kerberos = 1, doencrypt; +char dst_realm_buf[REALM_SZ], *dest_realm = NULL; +#endif + +#ifndef TIOCPKT_WINDOW +#define TIOCPKT_WINDOW 0x80 +#endif + +/* concession to Sun */ +#ifndef SIGUSR1 +#define SIGUSR1 30 +#endif + +int eight, litout, rem; + +int noescape; +u_char escapechar = '~'; + +char *speeds[] = { + "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", + "1800", "2400", "4800", "9600", "19200", "38400" +}; + +#ifdef OLDSUN +struct winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; +#else +#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) +#endif +struct winsize winsize; + +void catch_child __P((int)); +void copytochild __P((int)); +__dead void doit __P((long)); +__dead void done __P((int)); +void echo __P((char)); +u_int getescape __P((char *)); +void lostpeer __P((int)); +void mode __P((int)); +void msg __P((char *)); +void oob __P((int)); +int reader __P((int)); +void sendwindow __P((void)); +void setsignal __P((int)); +void sigwinch __P((int)); +void stop __P((char)); +__dead void usage __P((void)); +void writer __P((void)); +void writeroob __P((int)); + +#ifdef KERBEROS +void warning __P((const char *, ...)); +#endif +#ifdef OLDSUN +int get_window_size __P((int, struct winsize *)); +#endif + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + struct passwd *pw; + struct servent *sp; + struct sgttyb ttyb; + long omask; + int argoff, ch, dflag, one, uid; + char *host, *p, *user, term[1024]; + + argoff = dflag = 0; + one = 1; + host = user = NULL; + + if (p = rindex(argv[0], '/')) + ++p; + else + p = argv[0]; + + if (strcmp(p, "rlogin")) + host = p; + + /* handle "rlogin host flags" */ + if (!host && argc > 2 && argv[1][0] != '-') { + host = argv[1]; + argoff = 1; + } + +#ifdef KERBEROS +#define OPTIONS "8EKLde:k:l:x" +#else +#define OPTIONS "8EKLde:l:" +#endif + while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) + switch(ch) { + case '8': + eight = 1; + break; + case 'E': + noescape = 1; + break; + case 'K': +#ifdef KERBEROS + use_kerberos = 0; +#endif + break; + case 'L': + litout = 1; + break; + case 'd': + dflag = 1; + break; + case 'e': + noescape = 0; + escapechar = getescape(optarg); + break; +#ifdef KERBEROS + case 'k': + dest_realm = dst_realm_buf; + (void)strncpy(dest_realm, optarg, REALM_SZ); + break; +#endif + case 'l': + user = optarg; + break; +#ifdef CRYPT +#ifdef KERBEROS + case 'x': + doencrypt = 1; + des_set_key(cred.session, schedule); + break; +#endif +#endif + case '?': + default: + usage(); + } + optind += argoff; + argc -= optind; + argv += optind; + + /* if haven't gotten a host yet, do so */ + if (!host && !(host = *argv++)) + usage(); + + if (*argv) + usage(); + + if (!(pw = getpwuid(uid = getuid()))) { + (void)fprintf(stderr, "rlogin: unknown user id.\n"); + exit(1); + } + if (!user) + user = pw->pw_name; + + sp = NULL; +#ifdef KERBEROS + if (use_kerberos) { + sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); + if (sp == NULL) { + use_kerberos = 0; + warning("can't get entry for %s/tcp service", + doencrypt ? "eklogin" : "klogin"); + } + } +#endif + if (sp == NULL) + sp = getservbyname("login", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); + exit(1); + } + + (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); + if (ioctl(0, TIOCGETP, &ttyb) == 0) { + (void)strcat(term, "/"); + (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); + } + + (void)get_window_size(0, &winsize); + + (void)signal(SIGPIPE, lostpeer); + /* will use SIGUSR1 for window size hack, so hold it off */ + omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); + /* + * We set SIGURG and SIGUSR1 below so that an + * incoming signal will be held pending rather than being + * discarded. Note that these routines will be ready to get + * a signal by the time that they are unblocked below. + */ + (void)signal(SIGURG, copytochild); + (void)signal(SIGUSR1, writeroob); + +#ifdef KERBEROS +try_connect: + if (use_kerberos) { + struct hostent *hp; + + /* Fully qualify hostname (needed for krb_realmofhost). */ + hp = gethostbyname(host); + if (hp != NULL && !(host = strdup(hp->h_name))) { + (void)fprintf(stderr, "rlogin: %s\n", + strerror(ENOMEM)); + exit(1); + } + + rem = KSUCCESS; + errno = 0; + if (dest_realm == NULL) + dest_realm = krb_realmofhost(host); + +#ifdef CRYPT + if (doencrypt) + rem = krcmd_mutual(&host, sp->s_port, user, term, 0, + dest_realm, &cred, schedule); + else +#endif /* CRYPT */ + rem = krcmd(&host, sp->s_port, user, term, 0, + dest_realm); + if (rem < 0) { + use_kerberos = 0; + sp = getservbyname("login", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, + "rlogin: unknown service login/tcp.\n"); + exit(1); + } + if (errno == ECONNREFUSED) + warning("remote host doesn't support Kerberos"); + if (errno == ENOENT) + warning("can't provide Kerberos auth data"); + goto try_connect; + } + } else { +#ifdef CRYPT + if (doencrypt) { + (void)fprintf(stderr, + "rlogin: the -x flag requires Kerberos authentication.\n"); + exit(1); + } +#endif /* CRYPT */ + rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); + } +#else + rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); +#endif /* KERBEROS */ + + if (rem < 0) + exit(1); + + if (dflag && + setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) + (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", + strerror(errno)); + one = IPTOS_LOWDELAY; + if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) + perror("rlogin: setsockopt TOS (ignored)"); + + (void)setuid(uid); + doit(omask); + /*NOTREACHED*/ +} + +int child, defflags, deflflags, tabflag; +char deferase, defkill; +struct tchars deftc; +struct ltchars defltc; +struct tchars notc = { -1, -1, -1, -1, -1, -1 }; +struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; + +void +doit(omask) + long omask; +{ + struct sgttyb sb; + + (void)ioctl(0, TIOCGETP, (char *)&sb); + defflags = sb.sg_flags; + tabflag = defflags & TBDELAY; + defflags &= ECHO | CRMOD; + deferase = sb.sg_erase; + defkill = sb.sg_kill; + (void)ioctl(0, TIOCLGET, &deflflags); + (void)ioctl(0, TIOCGETC, &deftc); + notc.t_startc = deftc.t_startc; + notc.t_stopc = deftc.t_stopc; + (void)ioctl(0, TIOCGLTC, &defltc); + (void)signal(SIGINT, SIG_IGN); + setsignal(SIGHUP); + setsignal(SIGQUIT); + child = fork(); + if (child == -1) { + (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); + done(1); + } + if (child == 0) { + mode(1); + if (reader(omask) == 0) { + msg("connection closed."); + exit(0); + } + sleep(1); + msg("\007connection closed."); + exit(1); + } + + /* + * We may still own the socket, and may have a pending SIGURG (or might + * receive one soon) that we really want to send to the reader. When + * one of these comes in, the trap copytochild simply copies such + * signals to the child. We can now unblock SIGURG and SIGUSR1 + * that were set above. + */ + (void)sigsetmask(omask); + (void)signal(SIGCHLD, catch_child); + writer(); + msg("closed connection."); + done(0); +} + +/* trap a signal, unless it is being ignored. */ +void +setsignal(sig) + int sig; +{ + int omask = sigblock(sigmask(sig)); + + if (signal(sig, exit) == SIG_IGN) + (void)signal(sig, SIG_IGN); + (void)sigsetmask(omask); +} + +__dead void +done(status) + int status; +{ + int w, wstatus; + + mode(0); + if (child > 0) { + /* make sure catch_child does not snap it up */ + (void)signal(SIGCHLD, SIG_DFL); + if (kill(child, SIGKILL) >= 0) + while ((w = wait(&wstatus)) > 0 && w != child); + } + exit(status); +} + +int dosigwinch; + +/* + * This is called when the reader process gets the out-of-band (urgent) + * request to turn on the window-changing protocol. + */ +void +writeroob(signo) + int signo; +{ + if (dosigwinch == 0) { + sendwindow(); + (void)signal(SIGWINCH, sigwinch); + } + dosigwinch = 1; +} + +void +catch_child(signo) + int signo; +{ + union wait status; + int pid; + + for (;;) { + pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); + if (pid == 0) + return; + /* if the child (reader) dies, just quit */ + if (pid < 0 || (pid == child && !WIFSTOPPED(status))) + done((int)(status.w_termsig | status.w_retcode)); + } + /* NOTREACHED */ +} + +/* + * writer: write to remote: 0 -> line. + * ~. terminate + * ~^Z suspend rlogin process. + * ~ suspend rlogin process, but leave reader alone. + */ +void +writer() +{ + register int bol, local, n; + char c; + + bol = 1; /* beginning of line */ + local = 0; + for (;;) { + n = read(STDIN_FILENO, &c, 1); + if (n <= 0) { + if (n < 0 && errno == EINTR) + continue; + break; + } + /* + * If we're at the beginning of the line and recognize a + * command character, then we echo locally. Otherwise, + * characters are echo'd remotely. If the command character + * is doubled, this acts as a force and local echo is + * suppressed. + */ + if (bol) { + bol = 0; + if (!noescape && c == escapechar) { + local = 1; + continue; + } + } else if (local) { + local = 0; + if (c == '.' || c == deftc.t_eofc) { + echo(c); + break; + } + if (c == defltc.t_suspc || c == defltc.t_dsuspc) { + bol = 1; + echo(c); + stop(c); + continue; + } + if (c != escapechar) +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) + (void)des_write(rem, + (char *)&escapechar, 1); + else +#endif +#endif + (void)write(rem, &escapechar, 1); + } + +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + if (des_write(rem, &c, 1) == 0) { + msg("line gone"); + break; + } + } else +#endif +#endif + if (write(rem, &c, 1) == 0) { + msg("line gone"); + break; + } + bol = c == defkill || c == deftc.t_eofc || + c == deftc.t_intrc || c == defltc.t_suspc || + c == '\r' || c == '\n'; + } +} + +void +#if __STDC__ +echo(register char c) +#else +echo(c) + register char c; +#endif +{ + register char *p; + char buf[8]; + + p = buf; + c &= 0177; + *p++ = escapechar; + if (c < ' ') { + *p++ = '^'; + *p++ = c + '@'; + } else if (c == 0177) { + *p++ = '^'; + *p++ = '?'; + } else + *p++ = c; + *p++ = '\r'; + *p++ = '\n'; + (void)write(STDOUT_FILENO, buf, p - buf); +} + +void +#if __STDC__ +stop(char cmdc) +#else +stop(cmdc) + char cmdc; +#endif +{ + mode(0); + (void)signal(SIGCHLD, SIG_IGN); + (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); + (void)signal(SIGCHLD, catch_child); + mode(1); + sigwinch(0); /* check for size changes */ +} + +void +sigwinch(signo) + int signo; +{ + struct winsize ws; + + if (dosigwinch && get_window_size(0, &ws) == 0 && + bcmp(&ws, &winsize, sizeof(ws))) { + winsize = ws; + sendwindow(); + } +} + +/* + * Send the window size to the server via the magic escape + */ +void +sendwindow() +{ + struct winsize *wp; + char obuf[4 + sizeof (struct winsize)]; + + wp = (struct winsize *)(obuf+4); + obuf[0] = 0377; + obuf[1] = 0377; + obuf[2] = 's'; + obuf[3] = 's'; + wp->ws_row = htons(winsize.ws_row); + wp->ws_col = htons(winsize.ws_col); + wp->ws_xpixel = htons(winsize.ws_xpixel); + wp->ws_ypixel = htons(winsize.ws_ypixel); + +#ifdef CRYPT +#ifdef KERBEROS + if(doencrypt) + (void)des_write(rem, obuf, sizeof(obuf)); + else +#endif +#endif + (void)write(rem, obuf, sizeof(obuf)); +} + +/* + * reader: read from remote: line -> 1 + */ +#define READING 1 +#define WRITING 2 + +jmp_buf rcvtop; +int ppid, rcvcnt, rcvstate; +char rcvbuf[8 * 1024]; + +void +oob(signo) + int signo; +{ + struct sgttyb sb; + int atmark, n, out, rcvd; + char waste[BUFSIZ], mark; + + out = O_RDWR; + rcvd = 0; + while (recv(rem, &mark, 1, MSG_OOB) < 0) { + switch (errno) { + case EWOULDBLOCK: + /* + * Urgent data not here yet. It may not be possible + * to send it yet if we are blocked for output and + * our input buffer is full. + */ + if (rcvcnt < sizeof(rcvbuf)) { + n = read(rem, rcvbuf + rcvcnt, + sizeof(rcvbuf) - rcvcnt); + if (n <= 0) + return; + rcvd += n; + } else { + n = read(rem, waste, sizeof(waste)); + if (n <= 0) + return; + } + continue; + default: + return; + } + } + if (mark & TIOCPKT_WINDOW) { + /* Let server know about window size changes */ + (void)kill(ppid, SIGUSR1); + } + if (!eight && (mark & TIOCPKT_NOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~CBREAK; + sb.sg_flags |= RAW; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = -1; + notc.t_startc = -1; + (void)ioctl(0, TIOCSETC, (char *)¬c); + } + if (!eight && (mark & TIOCPKT_DOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~RAW; + sb.sg_flags |= CBREAK; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = deftc.t_stopc; + notc.t_startc = deftc.t_startc; + (void)ioctl(0, TIOCSETC, (char *)¬c); + } + if (mark & TIOCPKT_FLUSHWRITE) { + (void)ioctl(1, TIOCFLUSH, (char *)&out); + for (;;) { + if (ioctl(rem, SIOCATMARK, &atmark) < 0) { + (void)fprintf(stderr, "rlogin: ioctl: %s.\n", + strerror(errno)); + break; + } + if (atmark) + break; + n = read(rem, waste, sizeof (waste)); + if (n <= 0) + break; + } + /* + * Don't want any pending data to be output, so clear the recv + * buffer. If we were hanging on a write when interrupted, + * don't want it to restart. If we were reading, restart + * anyway. + */ + rcvcnt = 0; + longjmp(rcvtop, 1); + } + + /* oob does not do FLUSHREAD (alas!) */ + + /* + * If we filled the receive buffer while a read was pending, longjmp + * to the top to restart appropriately. Don't abort a pending write, + * however, or we won't know how much was written. + */ + if (rcvd && rcvstate == READING) + longjmp(rcvtop, 1); +} + +/* reader: read from remote: line -> 1 */ +int +reader(omask) + int omask; +{ + int pid, n, remaining; + char *bufp; + +#if BSD >= 43 || defined(SUNOS4) + pid = getpid(); /* modern systems use positives for pid */ +#else + pid = -getpid(); /* old broken systems use negatives */ +#endif + (void)signal(SIGTTOU, SIG_IGN); + (void)signal(SIGURG, oob); + ppid = getppid(); + (void)fcntl(rem, F_SETOWN, pid); + (void)setjmp(rcvtop); + (void)sigsetmask(omask); + bufp = rcvbuf; + for (;;) { + while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { + rcvstate = WRITING; + n = write(STDOUT_FILENO, bufp, remaining); + if (n < 0) { + if (errno != EINTR) + return (-1); + continue; + } + bufp += n; + } + bufp = rcvbuf; + rcvcnt = 0; + rcvstate = READING; + +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) + rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); + else +#endif +#endif + rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); + if (rcvcnt == 0) + return (0); + if (rcvcnt < 0) { + if (errno == EINTR) + continue; + (void)fprintf(stderr, "rlogin: read: %s.\n", + strerror(errno)); + return (-1); + } + } +} + +void +mode(f) + int f; +{ + struct ltchars *ltc; + struct sgttyb sb; + struct tchars *tc; + int lflags; + + (void)ioctl(0, TIOCGETP, (char *)&sb); + (void)ioctl(0, TIOCLGET, (char *)&lflags); + switch(f) { + case 0: + sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); + sb.sg_flags |= defflags|tabflag; + tc = &deftc; + ltc = &defltc; + sb.sg_kill = defkill; + sb.sg_erase = deferase; + lflags = deflflags; + break; + case 1: + sb.sg_flags |= (eight ? RAW : CBREAK); + sb.sg_flags &= ~defflags; + /* preserve tab delays, but turn off XTABS */ + if ((sb.sg_flags & TBDELAY) == XTABS) + sb.sg_flags &= ~TBDELAY; + tc = ¬c; + ltc = &noltc; + sb.sg_kill = sb.sg_erase = -1; + if (litout) + lflags |= LLITOUT; + break; + default: + return; + } + (void)ioctl(0, TIOCSLTC, (char *)ltc); + (void)ioctl(0, TIOCSETC, (char *)tc); + (void)ioctl(0, TIOCSETN, (char *)&sb); + (void)ioctl(0, TIOCLSET, (char *)&lflags); +} + +void +lostpeer(signo) + int signo; +{ + (void)signal(SIGPIPE, SIG_IGN); + msg("\007connection closed."); + done(1); +} + +/* copy SIGURGs to the child process. */ +void +copytochild(signo) + int signo; +{ + (void)kill(child, SIGURG); +} + +void +msg(str) + char *str; +{ + (void)fprintf(stderr, "rlogin: %s\r\n", str); +} + +#ifdef KERBEROS +/* VARARGS */ +void +#if __STDC__ +warning(const char *fmt, ...) +#else +warning(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + + (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, ".\n"); +} +#endif + +__dead void +usage() +{ + (void)fprintf(stderr, + "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", +#ifdef KERBEROS +#ifdef CRYPT + "8EKLx", " [-k realm] "); +#else + "8EKL", " [-k realm] "); +#endif +#else + "8EL", " "); +#endif + exit(1); +} + +/* + * The following routine provides compatibility (such as it is) between older + * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. + */ +#ifdef OLDSUN +int +get_window_size(fd, wp) + int fd; + struct winsize *wp; +{ + struct ttysize ts; + int error; + + if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) + return (error); + wp->ws_row = ts.ts_lines; + wp->ws_col = ts.ts_cols; + wp->ws_xpixel = 0; + wp->ws_ypixel = 0; + return (0); +} +#endif + +u_int +getescape(p) + register char *p; +{ + long val; + int len; + + if ((len = strlen(p)) == 1) /* use any single char, including '\' */ + return ((u_int)*p); + /* otherwise, \nnn */ + if (*p == '\\' && len >= 2 && len <= 4) { + val = strtol(++p, NULL, 8); + for (;;) { + if (!*++p) + return ((u_int)val); + if (*p < '0' || *p > '8') + break; + } + } + msg("illegal option value -- e"); + usage(); + /* NOTREACHED */ +} diff --git a/usr.bin/rs/Makefile b/usr.bin/rs/Makefile new file mode 100644 index 0000000..21da34d --- /dev/null +++ b/usr.bin/rs/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= rs + +.include diff --git a/usr.bin/rs/rs.1 b/usr.bin/rs/rs.1 new file mode 100644 index 0000000..07de48c --- /dev/null +++ b/usr.bin/rs/rs.1 @@ -0,0 +1,197 @@ +.\" 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. +.\" +.\" @(#)rs.1 8.2 (Berkeley) 12/30/93 +.\" +.TH RS 1 "December 30, 1993" +.UC 4 +.SH NAME +rs \- reshape a data array +.SH SYNOPSIS +\fBrs [ \-[csCS][\fRx\fB][kKgGw][\fRN\fB]tTeEnyjhHm ] [ \fRrows\fB [ \fRcols\fB ] ]\fR +.SH DESCRIPTION +.I Rs +reads the standard input, interpreting each line as a row +of blank-separated entries in an array, +transforms the array according to the options, +and writes it on the standard output. +With no arguments it transforms stream input into a columnar +format convenient for terminal viewing. +.PP +The shape of the input array is deduced from the number of lines +and the number of columns on the first line. +If that shape is inconvenient, a more useful one might be +obtained by skipping some of the input with the \fB\-k\fP option. +Other options control interpretation of the input columns. +.PP +The shape of the output array is influenced by the +.I rows +and +.I cols +specifications, which should be positive integers. +If only one of them is a positive integer, +.I rs +computes a value for the other which will accommodate +all of the data. +When necessary, missing data are supplied in a manner +specified by the options and surplus data are deleted. +There are options to control presentation of the output columns, +including transposition of the rows and columns. +.PP +The options are described below. +.IP \fB\-c\fRx +Input columns are delimited by the single character \fIx\fP. +A missing \fIx\fP is taken to be `^I'. +.IP \fB\-s\fRx +Like \fB\-c\fR, but maximal strings of \fIx\fP are delimiters. +.IP \fB\-C\fRx +Output columns are delimited by the single character \fIx\fP. +A missing \fIx\fP is taken to be `^I'. +.IP \fB\-S\fRx +Like \fB\-C\fR, but padded strings of \fIx\fP are delimiters. +.IP \fB\-t\fR +Fill in the rows of the output array using the columns of the +input array, that is, transpose the input while honoring any +.I rows +and +.I cols +specifications. +.IP \fB\-T\fR +Print the pure transpose of the input, ignoring any +.I rows +or +.I cols +specification. +.IP \fB\-k\fRN +Ignore the first \fIN\fR lines of input. +.IP \fB\-K\fRN +Like \fB\-k\fR, but print the ignored lines. +.IP \fB\-g\fRN +The gutter width (inter-column space), normally 2, is taken to be \fIN\fR. +.IP \fB\-G\fRN +The gutter width has \fIN\fR percent of the maximum +column width added to it. +.IP \fB\-e\fR +Consider each line of input as an array entry. +.IP \fB\-n\fR +On lines having fewer entries than the first line, +use null entries to pad out the line. +Normally, missing entries are taken from the next line of input. +.IP \fB\-y\fR +If there are too few entries to make up the output dimensions, +pad the output by recycling the input from the beginning. +Normally, the output is padded with blanks. +.IP \fB\-h\fR +Print the shape of the input array and do nothing else. +The shape is just the number of lines and the number of +entries on the first line. +.IP \fB\-H\fR +Like \fB\-h\fR, but also print the length of each line. +.IP \fB\-j\fR +Right adjust entries within columns. +.IP \fB\-w\fRN +The width of the display, normally 80, is taken to be the positive +integer \fIN\fP. +.IP \fB\-m\fR +Do not trim excess delimiters from the ends of the output array. +.PP +With no arguments, +.I rs +transposes its input, and assumes one array entry per input line +unless the first non-ignored line is longer than the display width. +Option letters which take numerical arguments interpret a missing +number as zero unless otherwise indicated. +.SH EXAMPLES +.de IC +.IP +.ss 36 +.ft B +.. +.de NC +.br +.ss 12 +.PP +.. +.I Rs +can be used as a filter to convert the stream output +of certain programs (e.g., +.IR spell , +.IR du , +.IR file , +.IR look , +.IR nm , +.IR who , +and +.IR wc (1)) +into a convenient ``window'' format, as in +.IC +who | rs +.NC +This function has been incorporated into the +.IR ls (1) +program, though for most programs with similar output +.I rs +suffices. +.PP +To convert stream input into vector output and back again, use +.IC +rs 1 0 | rs 0 1 +.NC +A 10 by 10 array of random numbers from 1 to 100 and +its transpose can be generated with +.IC +jot \-r 100 | rs 10 10 | tee array | rs \-T > tarray +.NC +In the editor +.IR vi (1), +a file consisting of a multi-line vector with 9 elements per line +can undergo insertions and deletions, +and then be neatly reshaped into 9 columns with +.IC +:1,$!rs 0 9 +.NC +Finally, to sort a database by the first line of each 4-line field, try +.IC +rs \-eC 0 4 | sort | rs \-c 0 1 +.NC +.SH SEE ALSO +jot(1), vi(1), sort(1), pr(1) +.SH BUGS +Handles only two dimensional arrays. + +The algorithm currently reads the whole file into memory, +so files that do not fit in memory will not be reshaped. + +Fields cannot be defined yet on character positions. + +Re-ordering of columns is not yet possible. + +There are too many options. diff --git a/usr.bin/rs/rs.c b/usr.bin/rs/rs.c new file mode 100644 index 0000000..429dadc --- /dev/null +++ b/usr.bin/rs/rs.c @@ -0,0 +1,546 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * rs - reshape a data array + * Author: John Kunze, Office of Comp. Affairs, UCB + * BEWARE: lots of unfinished edges + */ + +#include +#include +#include + +long flags; +#define TRANSPOSE 000001 +#define MTRANSPOSE 000002 +#define ONEPERLINE 000004 +#define ONEISEPONLY 000010 +#define ONEOSEPONLY 000020 +#define NOTRIMENDCOL 000040 +#define SQUEEZE 000100 +#define SHAPEONLY 000200 +#define DETAILSHAPE 000400 +#define RIGHTADJUST 001000 +#define NULLPAD 002000 +#define RECYCLE 004000 +#define SKIPPRINT 010000 +#define ICOLBOUNDS 020000 +#define OCOLBOUNDS 040000 +#define ONEPERCHAR 0100000 +#define NOARGS 0200000 + +short *colwidths; +short *cord; +short *icbd; +short *ocbd; +int nelem; +char **elem; +char **endelem; +char *curline; +int allocsize = BUFSIZ; +int curlen; +int irows, icols; +int orows, ocols; +int maxlen; +int skip; +int propgutter; +char isep = ' ', osep = ' '; +int owidth = 80, gutter = 2; + +void error __P((char *, char *)); +void getargs __P((int, char *[])); +void getfile __P((void)); +int getline __P((void)); +char *getlist __P((short **, char *)); +char *getnum __P((int *, char *, int)); +char **getptrs __P((char **)); +void prepfile __P((void)); +void prints __P((char *, int)); +void putfile __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + getargs(argc, argv); + getfile(); + if (flags & SHAPEONLY) { + printf("%d %d\n", irows, icols); + exit(0); + } + prepfile(); + putfile(); + exit(0); +} + +void +getfile() +{ + register char *p; + register char *endp; + register char **ep = 0; + int multisep = (flags & ONEISEPONLY ? 0 : 1); + int nullpad = flags & NULLPAD; + char **padto; + + while (skip--) { + getline(); + if (flags & SKIPPRINT) + puts(curline); + } + getline(); + if (flags & NOARGS && curlen < owidth) + flags |= ONEPERLINE; + if (flags & ONEPERLINE) + icols = 1; + else /* count cols on first line */ + for (p = curline, endp = curline + curlen; p < endp; p++) { + if (*p == isep && multisep) + continue; + icols++; + while (*p && *p != isep) + p++; + } + ep = getptrs(elem); + p = curline; + do { + if (flags & ONEPERLINE) { + *ep++ = curline; + if (maxlen < curlen) + maxlen = curlen; + irows++; + continue; + } + for (p = curline, endp = curline + curlen; p < endp; p++) { + if (*p == isep && multisep) + continue; /* eat up column separators */ + if (*p == isep) /* must be an empty column */ + *ep = ""; + else /* store column entry */ + *ep = p; + while (p < endp && *p != isep) + p++; /* find end of entry */ + *p = '\0'; /* mark end of entry */ + if (maxlen < p - *ep) /* update maxlen */ + maxlen = p - *ep; + ep++; /* prepare for next entry */ + } + irows++; /* update row count */ + if (nullpad) { /* pad missing entries */ + padto = elem + irows * icols; + while (ep < padto) + *ep++ = ""; + } + if (ep > endelem) /* if low on pointers */ + ep = getptrs(ep); /* get some more */ + } while (getline() != EOF); + *ep = 0; /* mark end of pointers */ + nelem = ep - elem; +} + +void +putfile() +{ + register char **ep; + register int i, j; + + ep = elem; + if (flags & TRANSPOSE) + for (i = 0; i < orows; i++) { + for (j = i; j < nelem; j += orows) + prints(ep[j], (j - i) / orows); + putchar('\n'); + } + else + for (i = 0; i < orows; i++) { + for (j = 0; j < ocols; j++) + prints(*ep++, j); + putchar('\n'); + } +} + +void +prints(s, col) + char *s; + int col; +{ + register int n; + register char *p = s; + + while (*p) + p++; + n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s)); + if (flags & RIGHTADJUST) + while (n-- > 0) + putchar(osep); + for (p = s; *p; p++) + putchar(*p); + while (n-- > 0) + putchar(osep); +} + +void +error(msg, s) + char *msg, *s; +{ + fprintf(stderr, "rs: "); + fprintf(stderr, msg, s); + fprintf(stderr, +"\nUsage: rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n"); + exit(1); +} + +void +prepfile() +{ + register char **ep; + register int i; + register int j; + char **lp; + int colw; + int max = 0; + int n; + + if (!nelem) + exit(0); + gutter += maxlen * propgutter / 100.0; + colw = maxlen + gutter; + if (flags & MTRANSPOSE) { + orows = icols; + ocols = irows; + } + else if (orows == 0 && ocols == 0) { /* decide rows and cols */ + ocols = owidth / colw; + if (ocols == 0) + fprintf(stderr, "Display width %d is less than column width %d\n", owidth, colw); + if (ocols > nelem) + ocols = nelem; + orows = nelem / ocols + (nelem % ocols ? 1 : 0); + } + else if (orows == 0) /* decide on rows */ + orows = nelem / ocols + (nelem % ocols ? 1 : 0); + else if (ocols == 0) /* decide on cols */ + ocols = nelem / orows + (nelem % orows ? 1 : 0); + lp = elem + orows * ocols; + while (lp > endelem) { + getptrs(elem + nelem); + lp = elem + orows * ocols; + } + if (flags & RECYCLE) { + for (ep = elem + nelem; ep < lp; ep++) + *ep = *(ep - nelem); + nelem = lp - elem; + } + if (!(colwidths = (short *) malloc(ocols * sizeof(short)))) + error("malloc: No gutter space", ""); + if (flags & SQUEEZE) { + if (flags & TRANSPOSE) + for (ep = elem, i = 0; i < ocols; i++) { + for (j = 0; j < orows; j++) + if ((n = strlen(*ep++)) > max) + max = n; + colwidths[i] = max + gutter; + } + else + for (i = 0; i < ocols; i++) { + for (j = i; j < nelem; j += ocols) + if ((n = strlen(ep[j])) > max) + max = n; + colwidths[i] = max + gutter; + } + } + /* for (i = 0; i < orows; i++) { + for (j = i; j < nelem; j += orows) + prints(ep[j], (j - i) / orows); + putchar('\n'); + } + else + for (i = 0; i < orows; i++) { + for (j = 0; j < ocols; j++) + prints(*ep++, j); + putchar('\n'); + }*/ + else + for (i = 0; i < ocols; i++) + colwidths[i] = colw; + if (!(flags & NOTRIMENDCOL)) { + if (flags & RIGHTADJUST) + colwidths[0] -= gutter; + else + colwidths[ocols - 1] = 0; + } + n = orows * ocols; + if (n > nelem && (flags & RECYCLE)) + nelem = n; + /*for (i = 0; i < ocols; i++) + fprintf(stderr, "%d ",colwidths[i]); + fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/ +} + +#define BSIZE 2048 +char ibuf[BSIZE]; /* two screenfuls should do */ + +int +getline() /* get line; maintain curline, curlen; manage storage */ +{ + static int putlength; + static char *endblock = ibuf + BSIZE; + register char *p; + register int c, i; + + if (!irows) { + curline = ibuf; + putlength = flags & DETAILSHAPE; + } + else if (skip <= 0) { /* don't waste storage */ + curline += curlen + 1; + if (putlength) /* print length, recycle storage */ + printf(" %d line %d\n", curlen, irows); + } + if (!putlength && endblock - curline < BUFSIZ) { /* need storage */ + /*ww = endblock-curline; tt += ww;*/ + /*printf("#wasted %d total %d\n",ww,tt);*/ + if (!(curline = (char *) malloc(BSIZE))) + error("File too large", ""); + endblock = curline + BSIZE; + /*printf("#endb %d curline %d\n",endblock,curline);*/ + } + for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++) + if ((c = getchar()) == EOF || c == '\n') + break; + *p = '\0'; + curlen = i - 1; + return(c); +} + +char ** +getptrs(sp) + char **sp; +{ + register char **p, **ep; + + for (;;) { + allocsize += allocsize; + if (!(p = (char **) malloc(allocsize * sizeof(char *)))) { + perror("rs"); + exit(1); + } + if ((endelem = p + allocsize - icols) <= p) { + free(p); + continue; + } + if (elem != 0) + free(elem); + ep = elem; + elem = p; + while (ep < sp) + *p++ = *ep++; + return(p); + } +} + +void +getargs(ac, av) + int ac; + char *av[]; +{ + register char *p; + + if (ac == 1) { + flags |= NOARGS | TRANSPOSE; + } + while (--ac && **++av == '-') + for (p = *av+1; *p; p++) + switch (*p) { + case 'T': + flags |= MTRANSPOSE; + case 't': + flags |= TRANSPOSE; + break; + case 'c': /* input col. separator */ + flags |= ONEISEPONLY; + case 's': /* one or more allowed */ + if (p[1]) + isep = *++p; + else + isep = '\t'; /* default is ^I */ + break; + case 'C': + flags |= ONEOSEPONLY; + case 'S': + if (p[1]) + osep = *++p; + else + osep = '\t'; /* default is ^I */ + break; + case 'w': /* window width, default 80 */ + p = getnum(&owidth, p, 0); + if (owidth <= 0) + error("Width must be a positive integer", ""); + break; + case 'K': /* skip N lines */ + flags |= SKIPPRINT; + case 'k': /* skip, do not print */ + p = getnum(&skip, p, 0); + if (!skip) + skip = 1; + break; + case 'm': + flags |= NOTRIMENDCOL; + break; + case 'g': /* gutter space */ + p = getnum(&gutter, p, 0); + break; + case 'G': + p = getnum(&propgutter, p, 0); + break; + case 'e': /* each line is an entry */ + flags |= ONEPERLINE; + break; + case 'E': + flags |= ONEPERCHAR; + break; + case 'j': /* right adjust */ + flags |= RIGHTADJUST; + break; + case 'n': /* null padding for missing values */ + flags |= NULLPAD; + break; + case 'y': + flags |= RECYCLE; + break; + case 'H': /* print shape only */ + flags |= DETAILSHAPE; + case 'h': + flags |= SHAPEONLY; + break; + case 'z': /* squeeze col width */ + flags |= SQUEEZE; + break; + /*case 'p': + ipagespace = atoi(++p); (default is 1) + break;*/ + case 'o': /* col order */ + p = getlist(&cord, p); + break; + case 'b': + flags |= ICOLBOUNDS; + p = getlist(&icbd, p); + break; + case 'B': + flags |= OCOLBOUNDS; + p = getlist(&ocbd, p); + break; + default: + error("Bad flag: %.1s", p); + } + /*if (!osep) + osep = isep;*/ + switch (ac) { + /*case 3: + opages = atoi(av[2]);*/ + case 2: + ocols = atoi(av[1]); + case 1: + orows = atoi(av[0]); + case 0: + break; + default: + error("Too many arguments. What do you mean by `%s'?", av[3]); + } +} + +char * +getlist(list, p) + short **list; + char *p; +{ + register int count = 1; + register char *t; + + for (t = p + 1; *t; t++) { + if (!isdigit(*t)) + error("Option %.1s requires a list of unsigned numbers separated by commas", t); + count++; + while (*t && isdigit(*t)) + t++; + if (*t != ',') + break; + } + if (!(*list = (short *) malloc(count * sizeof(short)))) + error("No list space", ""); + count = 0; + for (t = p + 1; *t; t++) { + (*list)[count++] = atoi(t); + printf("++ %d ", (*list)[count-1]); + fflush(stdout); + while (*t && isdigit(*t)) + t++; + if (*t != ',') + break; + } + (*list)[count] = 0; + return(t - 1); +} + +char * +getnum(num, p, strict) /* num = number p points to; if (strict) complain */ + int *num, strict; /* returns pointer to end of num */ + char *p; +{ + register char *t = p; + + if (!isdigit(*++t)) { + if (strict || *t == '-' || *t == '+') + error("Option %.1s requires an unsigned integer", p); + *num = 0; + return(p); + } + *num = atoi(t); + while (*++t) + if (!isdigit(*t)) + break; + return(--t); +} diff --git a/usr.bin/rsh/Makefile b/usr.bin/rsh/Makefile new file mode 100644 index 0000000..d9e511e --- /dev/null +++ b/usr.bin/rsh/Makefile @@ -0,0 +1,13 @@ +# @(#)Makefile 8.1 (Berkeley) 7/19/93 + +PROG= rsh +CFLAGS+=-DKERBEROS -DCRYPT +SRCS= rsh.c krcmd.c kcmd.c des_rw.c +DPADD= ${LIBKRB} ${LIBDES} +LDADD= -lkrb -ldes +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg +.PATH: ${.CURDIR}/../rlogin + +.include diff --git a/usr.bin/rsh/pathnames.h b/usr.bin/rsh/pathnames.h new file mode 100644 index 0000000..16753c8 --- /dev/null +++ b/usr.bin/rsh/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_RLOGIN "/usr/bin/rlogin" diff --git a/usr.bin/rsh/rsh.1 b/usr.bin/rsh/rsh.1 new file mode 100644 index 0000000..908e7eb --- /dev/null +++ b/usr.bin/rsh/rsh.1 @@ -0,0 +1,181 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rsh.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt RSH 1 +.Os BSD 4.2 +.Sh NAME +.Nm rsh +.Nd remote shell +.Sh SYNOPSIS +.Nm rsh +.Op Fl Kdnx +.Op Fl k Ar realm +.Op Fl l Ar username +.Ar host +.Op command +.Sh DESCRIPTION +.Nm Rsh +executes +.Ar command +on +.Ar host . +.Pp +.Nm Rsh +copies its standard input to the remote command, the standard +output of the remote command to its standard output, and the +standard error of the remote command to its standard error. +Interrupt, quit and terminate signals are propagated to the remote +command; +.Nm rsh +normally terminates when the remote command does. +The options are as follows: +.Bl -tag -width flag +.It Fl K +The +.Fl K +option turns off all Kerberos authentication. +.It Fl d +The +.Fl d +option turns on socket debugging (using +.Xr setsockopt 2 ) +on the +.Tn TCP +sockets used for communication with the remote host. +.It Fl k +The +.Fl k +option causes +.Nm rsh +to obtain tickets for the remote host in +.Ar realm +instead of the remote host's realm as determined by +.Xr krb_realmofhost 3 . +.It Fl l +By default, the remote username is the same as the local username. +The +.Fl l +option allows the remote name to be specified. +Kerberos authentication is used, and authorization is determined +as in +.Xr rlogin 1 . +.It Fl n +The +.Fl n +option redirects input from the special device +.Pa /dev/null +(see the +.Sx BUGS +section of this manual page). +.It Fl x +The +.Fl x +option turns on +.Tn DES +encryption for all data exchange. +This may introduce a significant delay in response time. +.El +.Pp +If no +.Ar command +is specified, you will be logged in on the remote host using +.Xr rlogin 1 . +.Pp +Shell metacharacters which are not quoted are interpreted on local machine, +while quoted metacharacters are interpreted on the remote machine. +For example, the command +.Pp +.Dl rsh otherhost cat remotefile >> localfile +.Pp +appends the remote file +.Ar remotefile +to the local file +.Ar localfile , +while +.Pp +.Dl rsh otherhost cat remotefile \&">>\&" other_remotefile +.Pp +appends +.Ar remotefile +to +.Ar other_remotefile . +.\" .Pp +.\" Many sites specify a large number of host names as commands in the +.\" directory /usr/hosts. +.\" If this directory is included in your search path, you can use the +.\" shorthand ``host command'' for the longer form ``rsh host command''. +.Sh FILES +.Bl -tag -width /etc/hosts -compact +.It Pa /etc/hosts +.El +.Sh SEE ALSO +.Xr rlogin 1 , +.Xr kerberos 3 , +.Xr krb_sendauth 3 , +.Xr krb_realmofhost 3 +.Sh HISTORY +The +.Nm rsh +command appeared in +.Bx 4.2 . +.Sh BUGS +If you are using +.Xr csh 1 +and put a +.Nm rsh +in the background without redirecting its input away from the terminal, +it will block even if no reads are posted by the remote command. +If no input is desired you should redirect the input of +.Nm rsh +to +.Pa /dev/null +using the +.Fl n +option. +.Pp +You cannot run an interactive command +(like +.Xr rogue 6 +or +.Xr vi 1 ) +using +.Nm rsh ; +use +.Xr rlogin 1 +instead. +.Pp +Stop signals stop the local +.Nm rsh +process only; this is arguably wrong, but currently hard to fix for reasons +too complicated to explain here. diff --git a/usr.bin/rsh/rsh.c b/usr.bin/rsh/rsh.c new file mode 100644 index 0000000..c663f79 --- /dev/null +++ b/usr.bin/rsh/rsh.c @@ -0,0 +1,480 @@ +/*- + * Copyright (c) 1983, 1990, 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 copyright[] = +"@(#) Copyright (c) 1983, 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rsh.c 8.3 (Berkeley) 4/6/94"; +#endif /* not lint */ + +/* + * $Source: mit/rsh/RCS/rsh.c,v $ + * $Header: mit/rsh/RCS/rsh.c,v 5.1 89/07/31 19:28:59 kfall Exp Locker: kfall $ + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +#ifdef KERBEROS +#include +#include + +CREDENTIALS cred; +Key_schedule schedule; +int use_kerberos = 1, doencrypt; +char dst_realm_buf[REALM_SZ], *dest_realm; +extern char *krb_realmofhost(); +#endif + +/* + * rsh - remote shell + */ +int rfd2; + +char *copyargs __P((char **)); +void sendsig __P((int)); +void talk __P((int, long, pid_t, int)); +void usage __P((void)); +void warning __P(()); + +int +main(argc, argv) + int argc; + char **argv; +{ + struct passwd *pw; + struct servent *sp; + long omask; + int argoff, asrsh, ch, dflag, nflag, one, rem; + pid_t pid; + uid_t uid; + char *args, *host, *p, *user; + + argoff = asrsh = dflag = nflag = 0; + one = 1; + host = user = NULL; + + /* if called as something other than "rsh", use it as the host name */ + if (p = strrchr(argv[0], '/')) + ++p; + else + p = argv[0]; + if (strcmp(p, "rsh")) + host = p; + else + asrsh = 1; + + /* handle "rsh host flags" */ + if (!host && argc > 2 && argv[1][0] != '-') { + host = argv[1]; + argoff = 1; + } + +#ifdef KERBEROS +#ifdef CRYPT +#define OPTIONS "8KLdek:l:nwx" +#else +#define OPTIONS "8KLdek:l:nw" +#endif +#else +#define OPTIONS "8KLdel:nw" +#endif + while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) + switch(ch) { + case 'K': +#ifdef KERBEROS + use_kerberos = 0; +#endif + break; + case 'L': /* -8Lew are ignored to allow rlogin aliases */ + case 'e': + case 'w': + case '8': + break; + case 'd': + dflag = 1; + break; + case 'l': + user = optarg; + break; +#ifdef KERBEROS + case 'k': + dest_realm = dst_realm_buf; + strncpy(dest_realm, optarg, REALM_SZ); + break; +#endif + case 'n': + nflag = 1; + break; +#ifdef KERBEROS +#ifdef CRYPT + case 'x': + doencrypt = 1; + des_set_key(cred.session, schedule); + break; +#endif +#endif + case '?': + default: + usage(); + } + optind += argoff; + + /* if haven't gotten a host yet, do so */ + if (!host && !(host = argv[optind++])) + usage(); + + /* if no further arguments, must have been called as rlogin. */ + if (!argv[optind]) { + if (asrsh) + *argv = "rlogin"; + execv(_PATH_RLOGIN, argv); + err(1, "can't exec %s", _PATH_RLOGIN); + } + + argc -= optind; + argv += optind; + + if (!(pw = getpwuid(uid = getuid()))) + errx(1, "unknown user id"); + if (!user) + user = pw->pw_name; + +#ifdef KERBEROS +#ifdef CRYPT + /* -x turns off -n */ + if (doencrypt) + nflag = 0; +#endif +#endif + + args = copyargs(argv); + + sp = NULL; +#ifdef KERBEROS + if (use_kerberos) { + sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); + if (sp == NULL) { + use_kerberos = 0; + warning("can't get entry for %s/tcp service", + doencrypt ? "ekshell" : "kshell"); + } + } +#endif + if (sp == NULL) + sp = getservbyname("shell", "tcp"); + if (sp == NULL) + errx(1, "shell/tcp: unknown service"); + +#ifdef KERBEROS +try_connect: + if (use_kerberos) { + struct hostent *hp; + + /* fully qualify hostname (needed for krb_realmofhost) */ + hp = gethostbyname(host); + if (hp != NULL && !(host = strdup(hp->h_name))) + err(1, NULL); + + rem = KSUCCESS; + errno = 0; + if (dest_realm == NULL) + dest_realm = krb_realmofhost(host); + +#ifdef CRYPT + if (doencrypt) + rem = krcmd_mutual(&host, sp->s_port, user, args, + &rfd2, dest_realm, &cred, schedule); + else +#endif + rem = krcmd(&host, sp->s_port, user, args, &rfd2, + dest_realm); + if (rem < 0) { + use_kerberos = 0; + sp = getservbyname("shell", "tcp"); + if (sp == NULL) + errx(1, "shell/tcp: unknown service"); + if (errno == ECONNREFUSED) + warning("remote host doesn't support Kerberos"); + if (errno == ENOENT) + warning("can't provide Kerberos auth data"); + goto try_connect; + } + } else { + if (doencrypt) + errx(1, "the -x flag requires Kerberos authentication"); + rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); + } +#else + rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); +#endif + + if (rem < 0) + exit(1); + + if (rfd2 < 0) + errx(1, "can't establish stderr"); + if (dflag) { + if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, + sizeof(one)) < 0) + warn("setsockopt"); + if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, + sizeof(one)) < 0) + warn("setsockopt"); + } + + (void)setuid(uid); + omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void)signal(SIGINT, sendsig); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + (void)signal(SIGQUIT, sendsig); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + (void)signal(SIGTERM, sendsig); + + if (!nflag) { + pid = fork(); + if (pid < 0) + err(1, "fork"); + } + +#ifdef KERBEROS +#ifdef CRYPT + if (!doencrypt) +#endif +#endif + { + (void)ioctl(rfd2, FIONBIO, &one); + (void)ioctl(rem, FIONBIO, &one); + } + + talk(nflag, omask, pid, rem); + + if (!nflag) + (void)kill(pid, SIGKILL); + exit(0); +} + +void +talk(nflag, omask, pid, rem) + int nflag; + long omask; + pid_t pid; + int rem; +{ + int cc, wc; + fd_set readfrom, ready, rembits; + char *bp, buf[BUFSIZ]; + + if (!nflag && pid == 0) { + (void)close(rfd2); + +reread: errno = 0; + if ((cc = read(0, buf, sizeof buf)) <= 0) + goto done; + bp = buf; + +rewrite: + FD_ZERO(&rembits); + FD_SET(rem, &rembits); + if (select(16, 0, &rembits, 0, 0) < 0) { + if (errno != EINTR) + err(1, "select"); + goto rewrite; + } + if (!FD_ISSET(rem, &rembits)) + goto rewrite; +#ifdef KERBEROS +#ifdef CRYPT + if (doencrypt) + wc = des_write(rem, bp, cc); + else +#endif +#endif + wc = write(rem, bp, cc); + if (wc < 0) { + if (errno == EWOULDBLOCK) + goto rewrite; + goto done; + } + bp += wc; + cc -= wc; + if (cc == 0) + goto reread; + goto rewrite; +done: + (void)shutdown(rem, 1); + exit(0); + } + + (void)sigsetmask(omask); + FD_ZERO(&readfrom); + FD_SET(rfd2, &readfrom); + FD_SET(rem, &readfrom); + do { + ready = readfrom; + if (select(16, &ready, 0, 0, 0) < 0) { + if (errno != EINTR) + err(1, "select"); + continue; + } + if (FD_ISSET(rfd2, &ready)) { + errno = 0; +#ifdef KERBEROS +#ifdef CRYPT + if (doencrypt) + cc = des_read(rfd2, buf, sizeof buf); + else +#endif +#endif + cc = read(rfd2, buf, sizeof buf); + if (cc <= 0) { + if (errno != EWOULDBLOCK) + FD_CLR(rfd2, &readfrom); + } else + (void)write(2, buf, cc); + } + if (FD_ISSET(rem, &ready)) { + errno = 0; +#ifdef KERBEROS +#ifdef CRYPT + if (doencrypt) + cc = des_read(rem, buf, sizeof buf); + else +#endif +#endif + cc = read(rem, buf, sizeof buf); + if (cc <= 0) { + if (errno != EWOULDBLOCK) + FD_CLR(rem, &readfrom); + } else + (void)write(1, buf, cc); + } + } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); +} + +void +sendsig(sig) + int sig; +{ + char signo; + + signo = sig; +#ifdef KERBEROS +#ifdef CRYPT + if (doencrypt) + (void)des_write(rfd2, &signo, 1); + else +#endif +#endif + (void)write(rfd2, &signo, 1); +} + +#ifdef KERBEROS +/* VARARGS */ +void +warning(va_alist) +va_dcl +{ + va_list ap; + char *fmt; + + (void)fprintf(stderr, "rsh: warning, using standard rsh: "); + va_start(ap); + fmt = va_arg(ap, char *); + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, ".\n"); +} +#endif + +char * +copyargs(argv) + char **argv; +{ + int cc; + char **ap, *args, *p; + + cc = 0; + for (ap = argv; *ap; ++ap) + cc += strlen(*ap) + 1; + if (!(args = malloc((u_int)cc))) + err(1, NULL); + for (p = args, ap = argv; *ap; ++ap) { + (void)strcpy(p, *ap); + for (p = strcpy(p, *ap); *p; ++p); + if (ap[1]) + *p++ = ' '; + } + return (args); +} + +void +usage() +{ + + (void)fprintf(stderr, + "usage: rsh [-nd%s]%s[-l login] host [command]\n", +#ifdef KERBEROS +#ifdef CRYPT + "x", " [-k realm] "); +#else + "", " [-k realm] "); +#endif +#else + "", " "); +#endif + exit(1); +} diff --git a/usr.bin/ruptime/Makefile b/usr.bin/ruptime/Makefile new file mode 100644 index 0000000..57f1e15 --- /dev/null +++ b/usr.bin/ruptime/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ruptime + +.include diff --git a/usr.bin/ruptime/ruptime.1 b/usr.bin/ruptime/ruptime.1 new file mode 100644 index 0000000..b3b0af8 --- /dev/null +++ b/usr.bin/ruptime/ruptime.1 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1983, 1990, 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. +.\" +.\" @(#)ruptime.1 8.2 (Berkeley) 4/5/94 +.\" +.Dd April 5, 1994 +.Dt RUPTIME 1 +.Os BSD 4.2 +.Sh NAME +.Nm ruptime +.Nd show host status of local machines +.Sh SYNOPSIS +.Nm ruptime +.Op Fl alrtu +.Sh DESCRIPTION +.Nm Ruptime +gives a status line like +.Ar uptime +for each machine on the local network; these are formed from packets +broadcast by each host on the network once a minute. +.Pp +Machines for which no status report has been received for 11 +minutes are shown as being down. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Users idle an hour or more are not counted unless the +.Fl a +flag is given. +.It Fl l +Sort by load average. +.It Fl r +Reverses the sort order. +.It Fl t +Sort by uptime. +.It Fl u +Sort by number of users. +.El +.Pp +The default listing is sorted by host name. +.Sh FILES +.Bl -tag -width /var/rwho/whod.* -compact +.It Pa /var/rwho/whod.* +data files +.El +.Sh SEE ALSO +.Xr rwho 1 +.Xr uptime 1 +.Sh HISTORY +.Nm Ruptime +appeared in +.Bx 4.2 . diff --git a/usr.bin/ruptime/ruptime.c b/usr.bin/ruptime/ruptime.c new file mode 100644 index 0000000..b9c17a7 --- /dev/null +++ b/usr.bin/ruptime/ruptime.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ruptime.c 8.2 (Berkeley) 4/5/94"; +#endif /* not lint */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct hs { + struct whod *hs_wd; + int hs_nusers; +} *hs; +struct whod awhod; + +#define ISDOWN(h) (now - (h)->hs_wd->wd_recvtime > 11 * 60) +#define WHDRSIZE (sizeof (awhod) - sizeof (awhod.wd_we)) + +size_t nhosts; +time_t now; +int rflg = 1; + +int hscmp __P((const void *, const void *)); +char *interval __P((time_t, char *)); +int lcmp __P((const void *, const void *)); +void morehosts __P((void)); +int tcmp __P((const void *, const void *)); +int ucmp __P((const void *, const void *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + struct dirent *dp; + struct hs *hsp; + struct whod *wd; + struct whoent *we; + DIR *dirp; + size_t hspace; + int aflg, cc, ch, fd, i, maxloadav; + char buf[sizeof(struct whod)]; + int (*cmp) __P((const void *, const void *)); + + aflg = 0; + cmp = hscmp; + while ((ch = getopt(argc, argv, "alrut")) != EOF) + switch (ch) { + case 'a': + aflg = 1; + break; + case 'l': + cmp = lcmp; + break; + case 'r': + rflg = -1; + break; + case 't': + cmp = tcmp; + break; + case 'u': + cmp = ucmp; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) + err(1, "%s", _PATH_RWHODIR); + + maxloadav = -1; + for (nhosts = hspace = 0; (dp = readdir(dirp)) != NULL;) { + if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5)) + continue; + if ((fd = open(dp->d_name, O_RDONLY, 0)) < 0) { + warn("%s", dp->d_name); + continue; + } + cc = read(fd, buf, sizeof(struct whod)); + (void)close(fd); + + if (cc < WHDRSIZE) + continue; + if (nhosts == hspace) { + if ((hs = + realloc(hs, (hspace += 40) * sizeof(*hs))) == NULL) + err(1, NULL); + hsp = hs + nhosts; + } + + if ((hsp->hs_wd = malloc((size_t)WHDRSIZE)) == NULL) + err(1, NULL); + memmove(hsp->hs_wd, buf, (size_t)WHDRSIZE); + + for (wd = (struct whod *)buf, i = 0; i < 2; ++i) + if (wd->wd_loadav[i] > maxloadav) + maxloadav = wd->wd_loadav[i]; + + for (hsp->hs_nusers = 0, + we = (struct whoent *)(buf + cc); --we >= wd->wd_we;) + if (aflg || we->we_idle < 3600) + ++hsp->hs_nusers; + ++hsp; + ++nhosts; + } + if (nhosts == 0) + errx(0, "no hosts in %s.", _PATH_RWHODIR); + + (void)time(&now); + qsort(hs, nhosts, sizeof(hs[0]), cmp); + for (i = 0; i < nhosts; i++) { + hsp = &hs[i]; + if (ISDOWN(hsp)) { + (void)printf("%-12.12s%s\n", hsp->hs_wd->wd_hostname, + interval(now - hsp->hs_wd->wd_recvtime, "down")); + continue; + } + (void)printf( + "%-12.12s%s, %4d user%s load %*.2f, %*.2f, %*.2f\n", + hsp->hs_wd->wd_hostname, + interval((time_t)hsp->hs_wd->wd_sendtime - + (time_t)hsp->hs_wd->wd_boottime, " up"), + hsp->hs_nusers, + hsp->hs_nusers == 1 ? ", " : "s,", + maxloadav >= 1000 ? 5 : 4, + hsp->hs_wd->wd_loadav[0] / 100.0, + maxloadav >= 1000 ? 5 : 4, + hsp->hs_wd->wd_loadav[1] / 100.0, + maxloadav >= 1000 ? 5 : 4, + hsp->hs_wd->wd_loadav[2] / 100.0); + } + exit(0); +} + +char * +interval(tval, updown) + time_t tval; + char *updown; +{ + static char resbuf[32]; + int days, hours, minutes; + + if (tval < 0 || tval > DAYSPERNYEAR * SECSPERDAY) { + (void)snprintf(resbuf, sizeof(resbuf), " %s ??:??", updown); + return (resbuf); + } + /* round to minutes. */ + minutes = (tval + (SECSPERMIN - 1)) / SECSPERMIN; + hours = minutes / MINSPERHOUR; + minutes %= MINSPERHOUR; + days = hours / HOURSPERDAY; + hours %= HOURSPERDAY; + if (days) + (void)snprintf(resbuf, sizeof(resbuf), + "%s %2d+%02d:%02d", updown, days, hours, minutes); + else + (void)snprintf(resbuf, sizeof(resbuf), + "%s %2d:%02d", updown, hours, minutes); + return (resbuf); +} + +#define HS(a) ((struct hs *)(a)) + +/* Alphabetical comparison. */ +int +hscmp(a1, a2) + const void *a1, *a2; +{ + return (rflg * + strcmp(HS(a1)->hs_wd->wd_hostname, HS(a2)->hs_wd->wd_hostname)); +} + +/* Load average comparison. */ +int +lcmp(a1, a2) + const void *a1, *a2; +{ + if (ISDOWN(HS(a1))) + if (ISDOWN(HS(a2))) + return (tcmp(a1, a2)); + else + return (rflg); + else if (ISDOWN(HS(a2))) + return (-rflg); + else + return (rflg * + (HS(a2)->hs_wd->wd_loadav[0] - HS(a1)->hs_wd->wd_loadav[0])); +} + +/* Number of users comparison. */ +int +ucmp(a1, a2) + const void *a1, *a2; +{ + if (ISDOWN(HS(a1))) + if (ISDOWN(HS(a2))) + return (tcmp(a1, a2)); + else + return (rflg); + else if (ISDOWN(HS(a2))) + return (-rflg); + else + return (rflg * (HS(a2)->hs_nusers - HS(a1)->hs_nusers)); +} + +/* Uptime comparison. */ +int +tcmp(a1, a2) + const void *a1, *a2; +{ + return (rflg * ( + (ISDOWN(HS(a2)) ? HS(a2)->hs_wd->wd_recvtime - now + : HS(a2)->hs_wd->wd_sendtime - HS(a2)->hs_wd->wd_boottime) + - + (ISDOWN(HS(a1)) ? HS(a1)->hs_wd->wd_recvtime - now + : HS(a1)->hs_wd->wd_sendtime - HS(a1)->hs_wd->wd_boottime) + )); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: ruptime [-alrut]\n"); + exit(1); +} diff --git a/usr.bin/rwho/Makefile b/usr.bin/rwho/Makefile new file mode 100644 index 0000000..328aa38 --- /dev/null +++ b/usr.bin/rwho/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= rwho + +.include diff --git a/usr.bin/rwho/rwho.1 b/usr.bin/rwho/rwho.1 new file mode 100644 index 0000000..f039b01 --- /dev/null +++ b/usr.bin/rwho/rwho.1 @@ -0,0 +1,80 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)rwho.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt RWHO 1 +.Os BSD 4.2 +.Sh NAME +.Nm rwho +.Nd who is logged in on local machines +.Sh SYNOPSIS +.Nm rwho +.Op Fl a +.Sh DESCRIPTION +The +.Nm rwho +command produces output similar to +.Xr who , +but for all machines on the local network. +If no report has been +received from a machine for 5 minutes then +.Nm rwho +assumes the machine is down, and does not report users last known +to be logged into that machine. +.Pp +If a users hasn't typed to the system for a minute or more, then +.Nm rwho +reports this idle time. If a user hasn't typed to the system for +an hour or more, then +the user will be omitted from the output of +.Nm rwho +unless the +.Fl a +flag is given. +.Sh FILES +.Bl -tag -width /var/rwho/rhowd.* -compact +.It Pa /var/rwho/whod.* +information about other machines +.El +.Sh SEE ALSO +.Xr ruptime 1 , +.Xr rwhod 8 +.Sh HISTORY +The +.Nm rwho +command +appeared in +.Bx 4.3 . +.Sh BUGS +This is unwieldy when the number of machines +on the local net is large. diff --git a/usr.bin/rwho/rwho.c b/usr.bin/rwho/rwho.c new file mode 100644 index 0000000..ee9c76d --- /dev/null +++ b/usr.bin/rwho/rwho.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rwho.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +DIR *dirp; + +struct whod wd; +int utmpcmp(); +#define NUSERS 1000 +struct myutmp { + char myhost[MAXHOSTNAMELEN]; + int myidle; + struct outmp myutmp; +} myutmp[NUSERS]; +int nusers; + +#define WHDRSIZE (sizeof (wd) - sizeof (wd.wd_we)) +/* + * this macro should be shared with ruptime. + */ +#define down(w,now) ((now) - (w)->wd_recvtime > 11 * 60) + +char *ctime(), *strcpy(); +time_t now; +int aflg; + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + int ch; + struct direct *dp; + int cc, width; + register struct whod *w = &wd; + register struct whoent *we; + register struct myutmp *mp; + int f, n, i; + time_t time(); + + while ((ch = getopt(argc, argv, "a")) != EOF) + switch((char)ch) { + case 'a': + aflg = 1; + break; + case '?': + default: + fprintf(stderr, "usage: rwho [-a]\n"); + exit(1); + } + if (chdir(_PATH_RWHODIR) || (dirp = opendir(".")) == NULL) { + perror(_PATH_RWHODIR); + exit(1); + } + mp = myutmp; + (void)time(&now); + while (dp = readdir(dirp)) { + if (dp->d_ino == 0 || strncmp(dp->d_name, "whod.", 5)) + continue; + f = open(dp->d_name, O_RDONLY); + if (f < 0) + continue; + cc = read(f, (char *)&wd, sizeof (struct whod)); + if (cc < WHDRSIZE) { + (void) close(f); + continue; + } + if (down(w,now)) { + (void) close(f); + continue; + } + cc -= WHDRSIZE; + we = w->wd_we; + for (n = cc / sizeof (struct whoent); n > 0; n--) { + if (aflg == 0 && we->we_idle >= 60*60) { + we++; + continue; + } + if (nusers >= NUSERS) { + printf("too many users\n"); + exit(1); + } + mp->myutmp = we->we_utmp; mp->myidle = we->we_idle; + (void) strcpy(mp->myhost, w->wd_hostname); + nusers++; we++; mp++; + } + (void) close(f); + } + qsort((char *)myutmp, nusers, sizeof (struct myutmp), utmpcmp); + mp = myutmp; + width = 0; + for (i = 0; i < nusers; i++) { + int j = strlen(mp->myhost) + 1 + strlen(mp->myutmp.out_line); + if (j > width) + width = j; + mp++; + } + mp = myutmp; + for (i = 0; i < nusers; i++) { + char buf[BUFSIZ]; + (void)sprintf(buf, "%s:%s", mp->myhost, mp->myutmp.out_line); + printf("%-8.8s %-*s %.12s", + mp->myutmp.out_name, + width, + buf, + ctime((time_t *)&mp->myutmp.out_time)+4); + mp->myidle /= 60; + if (mp->myidle) { + if (aflg) { + if (mp->myidle >= 100*60) + mp->myidle = 100*60 - 1; + if (mp->myidle >= 60) + printf(" %2d", mp->myidle / 60); + else + printf(" "); + } else + printf(" "); + printf(":%02d", mp->myidle % 60); + } + printf("\n"); + mp++; + } + exit(0); +} + +utmpcmp(u1, u2) + struct myutmp *u1, *u2; +{ + int rc; + + rc = strncmp(u1->myutmp.out_name, u2->myutmp.out_name, 8); + if (rc) + return (rc); + rc = strncmp(u1->myhost, u2->myhost, 8); + if (rc) + return (rc); + return (strncmp(u1->myutmp.out_line, u2->myutmp.out_line, 8)); +} diff --git a/usr.bin/sccs/Makefile b/usr.bin/sccs/Makefile new file mode 100644 index 0000000..0ee9d1b --- /dev/null +++ b/usr.bin/sccs/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= sccs + +.include diff --git a/usr.bin/sccs/PSD.doc/Makefile b/usr.bin/sccs/PSD.doc/Makefile new file mode 100644 index 0000000..4d2ba7f --- /dev/null +++ b/usr.bin/sccs/PSD.doc/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= psd/14.sccs +SRCS= sccs.me +MACROS= -me + +paper.ps: ${SRCS} + ${ROFF} ${SRCS} > ${.TARGET} + +.include diff --git a/usr.bin/sccs/PSD.doc/sccs.me b/usr.bin/sccs/PSD.doc/sccs.me new file mode 100644 index 0000000..ab598c2 --- /dev/null +++ b/usr.bin/sccs/PSD.doc/sccs.me @@ -0,0 +1,1608 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)sccs.me 8.1 (Berkeley) 6/8/93 +.\" +.eh '\fRPSD:14-%\fP''\fRAn Introduction to the Source Code Control System\fP' +.oh '\fRAn Introduction to the Source Code Control System\fP''\fRPSD:14-%\fP' +.ds S \s-1SCCS\s0 +.ds I \s-1SID\s0 +.nr bi 8n +.ev 1 \" only for keeps +.ss 16 +.ev +.\".he '\*S Introduction''%' +.+c +.(l C +.sz 14 +.b +An Introduction to the +Source Code Control System +.sz +.r +.sp +Eric Allman +.i "Project Ingres" +.i "University of California at Berkeley" +.)l +.sp 3 +.pp +.(f +This is version 1.21 of this document. +It was last modified on 12/5/80. +.)f +This document gives a quick introduction +to using the Source Code Control System +(\*S). +The presentation is geared to programmers +who are more concerned with +what +to do to get a task done +rather than how it works; +for this reason some of the examples +are not well explained. +For details of what the magic options do, +see the section on +.q "Further Information" . +.(l F +This is a working document. +Please send any comments or suggestions +to eric@Berkeley.Edu. +.)l +.sh 1 "Introduction" +.pp +\*S is a source management system. +Such a system maintains a record of versions of a system; +a record is kept with each set of changes +of what the changes are, +why they were made, +and who made them and when. +Old versions can be recovered, +and different versions can be maintained simultaneously. +In projects with more than one person, +\*S will insure that two people are not +editing the same file at the same time. +.pp +All versions of your program, +plus the log and other information, +is kept in a file called the +.q "s-file" . +There are three major operations +that can be performed on the s-file: +.np +Get a file for compilation (not for editing). +This operation retrieves a version of the file +from the s-file. +By default, the latest version is retrieved. +This file is intended for compilation, printing, or whatever; +it is specifically NOT intended to be edited +or changed in any way; +any changes made to a file retrieved +in this way will probably be lost. +.np +Get a file for editing. +This operation also retrieves a version of the file +from the s-file, +but this file is intended to be edited and then +incorporated back into the s-file. +Only one person may be editing a file at one time. +.np +Merge a file back into the s-file. +This is the companion operation to (2). +A new version number is assigned, +and comments are saved explaining why this change was made. +.sh 1 "Learning the Lingo" +.pp +There are a number of terms that are worth learning +before we go any farther. +.sh 2 "S-file" +.pp +The s-file +is a single file that holds all the different versions +of your file. +The s-file is stored in +differential format; +.i i.e. , +only the differences between versions are stored, +rather than the entire text of the new version. +This saves disk space +and allows selective changes to be removed later. +Also included in the s-file +is some header information for each version, +including the comments given by the person who +created the version explaining why the changes were made. +.sh 2 "Deltas" +.pp +Each set of changes to the s-file +(which is approximately [but not exactly!] equivalent +to a version of the file) +is called a +.i delta . +Although technically a delta only includes the +.i changes +made, +in practice +it is usual for +each delta to be made with respect to +all the deltas that have occurred before\**. +.(f +\**This matches normal usage, where the previous changes are not saved +at all, +so all changes are automatically based on all other changes +that have happened through history. +.)f +However, +it is possible to get a version of the file +that has selected deltas removed out of the middle +of the list of changes \*- +equivalent to removing your changes later. +.sh 2 "\*I's (or, version numbers)" +.pp +A \*I +(\*S Id) +is a number that represents a delta. +This is normally a two-part number +consisting of a +.q release +number and a +.q level +number. +Normally the release number stays the same, +however, +it is possible to move into a new release +if some major change is being made. +.pp +Since all past deltas are normally applied, +the \*I of the final delta applied +can be used to represent a version number of the file +as a whole. +.sh 2 "Id keywords" +.pp +When you get a version of a file +with intent to compile and install it +(\c +.i i.e. , +something other than edit it), +some special keywords are expanded inline +by \*S. +These +.i "Id Keywords" +can be used to include the current version number +or other information into the file. +All id keywords are of the form +.b % \c +.i x \c +.b % , +where +.i x +is an upper case letter. +For example, +.b %\&I\&% +is the \*I of the latest delta applied, +.b %\&W\&% +includes the module name, +\*I, +and a mark that makes it findable by a program, +and +.b %\&G\&% +is the date of the latest delta applied. +There are many others, +most of which are of dubious usefulness. +.pp +When you get a file for editing, +the id keywords are not expanded; +this is so that after you put them back in to the s-file, +they will be expanded automatically on each new version. +But notice: if you were to get them +expanded accidently, +then your file would appear to be the same version +forever more, +which would of course defeat the purpose. +Also, +if you should install a version of the program +without expanding the id keywords, +it will be impossible to tell what version it is +(since all it will have is +.q %\&W\&% +or whatever). +.sh 1 "Creating \*S Files" +.pp +To put source files +into +\*S +format, run the following shell script from csh: +.(b +mkdir SCCS save +foreach i (*.[ch]) + sccs admin \-i$i $i + mv $i save/$i +end +.)b +This will put the named files +into s-files +in the subdirectory +.q SCCS +The files will be removed from the current directory +and hidden away in the directory +.q save , +so the next thing you will probably want to do +is to get all the files +(described below). +When you are convinced that +\*S has correctly created the s-files, +you should remove the directory +.q save . +.pp +If you want to have id keywords in the files, +it is best to put them in before you create the s-files. +If you do not, +.i admin +will print +.q "No Id Keywords (cm7)" , +which is a warning message only. +.sh 1 "Getting Files for Compilation" +.pp +To get a copy of the latest version +of a file, +run +.(b +sccs get prog.c +.)b +\*S will respond: +.(b +1.1 +87 lines +.)b +meaning that version 1.1 was retrieved\** +.(f +\**Actually, +the \*I of the final delta applied was 1.1. +.)f +and that it has 87 lines. +The file +.i prog.c +will be created +in the current directory. +The file will be read-only +to remind you that you are not +supposed to change it. +.pp +This copy of the file +should not be changed, +since \*S is unable +to merge the changes +back into the s-file. +If you do make changes, +they will be lost the next time +someone does a +.i get . +.sh 1 "Changing Files (or, Creating Deltas)" +.sh 2 "Getting a copy to edit" +.pp +To edit a source file, +you must first get it, +requesting permission to edit it\**: +.(f +\**The +.q "edit" +command is equivalent to using the \-e +flag to +.i "get" , +as: +.(l +sccs get \-e prog.c +.)l +Keep this in mind when reading other documentation. +.)f +.(b +sccs edit prog.c +.)b +The response will be the same as with +.i get +except that it will also say: +.(b +New delta 1.2 +.)b +You then edit it, +using a standard text editor: +.(b +vi prog.c +.)b +.sh 2 "Merging the changes back into the s-file" +.pp +When the desired changes are made, +you can put your changes into the +\*S +file using the +.i delta +command: +.(b +sccs delta prog.c +.)b +.pp +Delta will prompt you for +.q "comments?" +before it merges the changes in. +At this prompt you should type a one-line description +of what the changes mean +(more lines can be entered by ending each line +except the last with a backslash\**). +.(f +\**Yes, this is a stupid default. +.)f +.i Delta +will then type: +.(b +1.2 +5 inserted +3 deleted +84 unchanged +.)b +saying that delta 1.2 was created, +and it inserted five lines, +removed three lines, +and left 84 lines unchanged\**. +.(f +\**Changes to a line are counted as a line deleted +and a line inserted. +.)f +The +.i prog.c +file will be removed; +it can be retrieved +using +.i get . +.sh 2 "When to make deltas" +.pp +It is probably unwise to make a delta +before every recompilation or test; +otherwise, +you tend to get a lot of deltas with comments like +.q "fixed compilation problem in previous delta" +or +.q "fixed botch in 1.3" . +However, +it is very important to delta everything +before installing a module for general use. +A good technique is to edit the files you need, +make all necessary changes and tests, +compiling and editing as often as necessary +without making deltas. +When you are satisfied that you have a working version, +delta everything being edited, +re-get them, +and recompile everything. +.sh 2 "What's going on: the info command" +.pp +To find out what files where being edited, +you can use: +.(b +sccs info +.)b +to print out all the files being edited +and other information such as the name of the user +who did the edit. +Also, +the command: +.(b +sccs check +.)b +is nearly equivalent to the +.i info +command, +except that it is silent if nothing is being edited, +and returns non-zero exit status if anything is being edited; +it can be used in an +.q install +entry in a makefile +to abort the install +if anything has not been properly deltaed. +.pp +If you know that everything being edited should be deltaed, +you can use: +.(b +sccs delta \`sccs tell\` +.)b +The +.i tell +command is similar to +.i info +except that only the names of files being edited +are output, +one per line. +.pp +All of these commands take a +.b \-b +flag +to ignore +.q branches +(alternate versions, described later) +and the +.b \-u +flag to only give files being edited by you. +The +.b \-u +flag takes an optional +.i user +argument, +giving only files being edited by that user. +For example, +.(b +sccs info \-ujohn +.)b +gives a listing of files being edited by john. +.sh 2 "ID keywords" +.pp +Id keywords can be inserted into your file +that will be expanded automatically by +.i get . +For example, +a line such as: +.(b +static char SccsId[] = "%\&W\&%\et%\&G\&%"; +.)b +will be replaced with something like: +.(b +static char SccsId[] = "@\&(#)prog.c 1.2 08/29/80"; +.)b +This tells you +the name and version +of the source file +and the time the delta was created. +The string +.q "@\&(#)" +is a special string +which signals the beginning +of an +\*S +Id keyword. +.sh 3 "The what command" +.pp +To find out what version of a program +is being run, +use: +.(b +sccs what prog.c /usr/bin/prog +.)b +which will print all strings +it finds that +begin with +.q "@\&(#)" . +This works on all types of files, +including binaries and libraries. +For example, the above command will output something like: +.(b +prog.c: + prog.c 1.2 08/29/80 +/usr/bin/prog: + prog.c 1.1 02/05/79 +.)b +From this I can see +that the source that I have in prog.c +will not compile into the same version +as the binary in /usr/bin/prog. +.sh 3 "Where to put id keywords" +.pp +ID keywords can be inserted anywhere, +including in comments, +but +Id Keywords that are compiled into the object module +are especially useful, +since it lets you find out what version of +the object is being run, +as well as the source. +However, +there is a cost: +data space is used up to store +the keywords, +and on small address space machines +this may be prohibitive. +.pp +When you put id keywords into header files, +it is important that you assign them to different variables. +For example, you might use: +.(b +static char AccessSid[] = "%\&W\&% %\&G\&%"; +.)b +in the file +.i access.h +and: +.(b +static char OpsysSid[] = "%\&W\&% %\&G\&%"; +.)b +in the file +.i opsys.h . +Otherwise, +you will get compilation errors because +.q SccsId +is redefined. +The problem with this is that if the header file +is included by many modules that are loaded together, +the version number of that header file is included +in the object module many times; +you may find it more to your taste +to put id keywords in header files +in comments. +.sh 2 "Keeping \*I's consistent across files" +.pp +With some care, +it is possible to keep the \*I's consistent +in multi-file systems. +The trick here is to always +.i edit +all files +at once. +The changes can then be made +to whatever files are necessary +and then all files +(even those not changed) +are redeltaed. +This can be done fairly easily +by just specifying the name of the directory +that the \*S files are in: +.(b +sccs edit SCCS +.)b +which will +.i edit +all files in that directory. +To make the delta, use: +.(b +sccs delta SCCS +.)b +You will be prompted for comments only once. +.sh 2 "Creating new releases" +.pp +When you want to create a new release +of a program, +you can specify the release number you want to create +on the +.i edit +command. +For example: +.(b +sccs edit \-r2 prog.c +.)b +will cause the next delta to be in release two +(that is, +it will be numbered 2.1). +Future deltas will automatically be in release two. +To change the release number +of an entire system, +use: +.(b +sccs edit \-r2 SCCS +.)b +.sh 1 "Restoring Old Versions" +.sh 2 "Reverting to old versions" +.pp +Suppose that after delta 1.2 +was stable +you made and released a delta 1.3. +But this introduced a bug, +so you made a delta 1.4 to correct it. +But 1.4 was still buggy, +and you decided you wanted to go back +to the old version. +You could +revert to delta 1.2 +by choosing the \*I in a get: +.(b +sccs get \-r1.2 prog.c +.)b +This will produce a version of +.i prog.c +that is delta 1.2 +that can be reinstalled so that work can proceed. +.pp +In some cases you don't know +what the \*I of the delta you want is. +However, +you can revert to the version of the program +that was running as of a certain date +by using the +.b \-c +(cutoff) flag. +For example, +.(b +sccs get \-c800722120000 prog.c +.)b +will retrieve whatever version was current +as of July 22, 1980 +at 12:00 noon. +Trailing components can be stripped off +(defaulting to their highest legal value), +and punctuation can be inserted in the obvious +places; +for example, +the above line could be equivalently stated: +.(b +sccs get \-c"80/07/22 12:00:00" prog.c +.)b +.sh 2 "Selectively deleting old deltas" +.pp +Suppose that you later decided +that you liked the changes in delta 1.4, +but that delta 1.3 should be removed. +You could do this by +.i excluding +delta 1.3: +.(b +sccs edit \-x1.3 prog.c +.)b +When delta 1.5 is made, +it will include the changes made +in delta 1.4, +but will exclude the changes made +in delta 1.3. +You can exclude a range of deltas +using a dash. +For example, +if you want to get rid of 1.3 and 1.4 +you can use: +.(b +sccs edit \-x1.3\-1.4 prog.c +.)b +which will exclude all deltas from 1.3 to 1.4. +Alternatively, +.(b +sccs edit \-x1.3\-1 prog.c +.)b +will exclude a range of deltas +from 1.3 to the current highest delta in release 1. +.pp +In certain cases when using +.b \-x +(or +.b \-i ; +see below) +there will be conflicts +between versions; +for example, it may be necessary +to both include and delete +a particular line. +If this happens, +\*S always prints out a message +telling the range of lines effected; +these lines should then be examined very carefully +to see if the version \*S got +is ok. +.pp +Since each delta +(in the sense of +.q "a set of changes" ) +can be excluded at will, +that this makes it most useful +to put each semantically distinct change +into its own delta. +.sh 1 "Auditing Changes" +.sh 2 "The prt command" +.pp +When you created a delta, +you presumably gave a reason for the delta +to the +.q "comments?" +prompt. +To print out these comments later, +use: +.(b +sccs prt prog.c +.)b +This will produce +a report +for each delta +of the \*I, +time and date of creation, +user who created the delta, +number of lines inserted, deleted, and unchanged, +and the comments associated with the delta. +For example, the output of the above command might be: +.(b +D 1.2 80/08/29 12:35:31 bill 2 1 00005/00003/00084 +removed "-q" option +.sp \n(psu +D 1.1 79/02/05 00:19:31 eric 1 0 00087/00000/00000 +date and time created 80/06/10 00:19:31 by eric +.)b +.sh 2 "Finding why lines were inserted" +.pp +To find out +why you inserted lines, +you can get a copy of the file +with each line +preceded by the \*I that created it: +.(b +sccs get \-m prog.c +.)b +You can then find out +what this delta did +by printing the comments using +.i prt . +.pp +To find out what lines are associated with a particular delta +(\c +.i e.g. , +1.3), +use: +.(b +sccs get \-m \-p prog.c \(bv grep \'^1.3\' +.)b +The +.b \-p +flag causes \*S to output the generated source +to the standard output rather than to a file. +.sh 2 "Finding what changes you have made" +.pp +When you are editing a file, +you can find out what changes you have made using: +.(b +sccs diffs prog.c +.)b +Most of the ``diff'' flags can be used. +To pass the +.b \-c +flag, +use +.b \-C . +.pp +To compare two versions that are in deltas, +use: +.(b +sccs sccsdiff -r1.3 -r1.6 prog.c +.)b +to see the differences between delta 1.3 and delta 1.6. +.sh 1 "Shorthand Notations" +.pp +There are several sequences of commands that get +executed frequently. +.i Sccs +tries to make it easy to do these. +.sh 2 "Delget" +.pp +A frequent requirement is to make a delta of some file +and then get that file. +This can be done by using: +.(b +sccs delget prog.c +.)b +which is entirely equivalent to using: +.(b +sccs delta prog.c +sccs get prog.c +.)b +The +.q deledit +command is equivalent to +.q delget +except that the +.q edit +command is used +instead of the +.q get +command. +.sh 2 "Fix" +.pp +Frequently, there are small bugs +in deltas, +e.g., compilation errors, +for which there is no reason to maintain an audit trail. +To +.i replace +a delta, use: +.(b +sccs fix \-r1.4 prog.c +.)b +This will get a copy of delta 1.4 of prog.c for you to edit +and then delete delta 1.4 from the \*S file. +When you do a delta of prog.c, +it will be delta 1.4 again. +The \-r flag must be specified, +and the delta that is specified must be a leaf delta, +i.e., no other deltas may have been made subsequent +to the creation of that delta. +.sh 2 "Unedit" +.pp +If you found you edited a file +that you did not want to edit, +you can back out by using: +.(b +sccs unedit prog.c +.)b +.sh 2 "The \-d flag" +.pp +If you are working on a project +where the \*S code is in a directory somewhere, +you may be able to simplify things +by using a shell alias. +For example, +the alias: +.(b +alias syssccs sccs \-d/usr/src +.)b +will allow you to issue commands such as: +.(b +syssccs edit cmd/who.c +.)b +which will look for the file +.q "/usr/src/cmd/SCCS/who.c" . +The file +.q who.c +will always be created in your current directory +regardless of the value of the \-d flag. +.sh 1 "Using \*S on a Project" +.pp +Working on a project with several people +has its own set of special problems. +The main problem occurs when two people +modify a file at the same time. +\*S prevents this by locking an s-file +while it is being edited. +.pp +As a result, +files should not be reserved for editing +unless they are actually being edited at the time, +since this will prevent other people on the project +from making necessary changes. +For example, +a good scenario for working might be: +.(b +sccs edit a.c g.c t.c +vi a.c g.c t.c +# do testing of the (experimental) version +sccs delget a.c g.c t.c +sccs info +# should respond "Nothing being edited" +make install +.)b +.pp +As a general rule, +all source files should be deltaed +before installing the program for general use. +This will insure that it is possible +to restore any version in use at any time. +.sh 1 "Saving Yourself" +.sh 2 "Recovering a munged edit file" +.pp +Sometimes you may find +that you have destroyed or trashed +a file that you were trying to edit\**. +.(f +\**Or given up and decided to start over. +.)f +Unfortunately, +you can't just remove it +and re-\c +.i edit +it; +\*S keeps track +of the fact +that someone is trying to edit it, +so it won't let you do it again. +Neither can you just get it using +.i get , +since that would expand the Id keywords. +Instead, +you can say: +.(b +sccs get \-k prog.c +.)b +This will not expand the Id keywords, +so it is safe to do a delta +with it. +.pp +Alternately, +you can +.i unedit +and +.i edit +the file. +.sh 2 "Restoring the s-file" +.pp +In particularly bad circumstances, +the \*S file itself +may get munged. +The most common way this happens +is that it gets edited. +Since \*S keeps a checksum, +you will get errors every time you read the file. +To fix this checksum, use: +.(b +sccs admin \-z prog.c +.)b +.sh 1 "Using the Admin Command" +.pp +There are a number of parameters that can be set +using the +.i admin +command. +The most interesting of these are flags. +Flags can be added by using the +.b \-f +flag. +For example: +.(b +sccs admin \-fd1 prog.c +.)b +sets the +.q d +flag to the value +.q 1 . +This flag can be deleted by using: +.(b +sccs admin \-dd prog.c +.)b +The most useful flags are: +.nr ii 7n +.ip "b" +Allow branches to be made using the +\-b +flag to +.i edit . +.ip "d\fISID\fP" +Default \*I to be used on a +.i get +or +.i edit . +If this is just a release number +it constrains the +version +to a particular release only. +.ip "i" +Give a fatal error +if there are no Id Keywords in a file. +This is useful to guarantee that a version of the +file does not get merged into the s-file +that has the Id Keywords inserted as constants +instead of internal forms. +.ip "y" +The +.q type +of the module. +Actually, +the value of this flag is unused by \*S +except that it replaces the +.b %\&Y\&% +keyword. +.pp +The +.b \-t\fIfile\fR +flag can be used +to store descriptive text +from +.i file . +This descriptive text might be the documentation +or a design and implementation document. +Using the +.b \-t +flag insures that if the \*S file is sent, +the documentation will be sent also. +If +.i file +is omitted, +the descriptive text is deleted. +To see the descriptive text, +use +.q "prt \-t" . +.pp +The +.i admin +command can be used safely +any number of times on files. +A file need not be gotten +for +.i admin +to work. +.sh 1 "Maintaining Different Versions (Branches)" +.pp +Sometimes it is convenient +to maintain an experimental version of a program +for an extended period +while normal maintenance continues +on the version in production. +This can be done using a +.q branch. +Normally deltas continue in a straight line, +each depending on the delta before. +Creating a branch +.q "forks off" +a version of the program. +.pp +The ability to create branches +must be enabled in advance using: +.(b +sccs admin \-fb prog.c +.)b +The +.b \-fb +flag can be specified when the +\*S file is first created. +.sh 2 "Creating a branch" +.pp +To create a branch, use: +.(b +sccs edit \-b prog.c +.)b +This will create a branch +with (for example) \*I 1.5.1.1. +The deltas for this version +will be numbered +1.5.1.\c +.i n . +.sh 2 "Getting from a branch" +.pp +Deltas in a branch are normally not included +when you do a get. +To get these versions, +you will have to say: +.(b +sccs get \-r1.5.1 prog.c +.)b +.sh 2 "Merging a branch back into the main trunk" +.pp +At some point you will have finished the experiment, +and if it was successful +you will want to incorporate it into the release version. +But in the meantime +someone may have created a delta 1.6 +that you don't want to lose. +The commands: +.(b +sccs edit \-i1.5.1.1\-1.5.1 prog.c +sccs delta prog.c +.)b +will merge all of your changes +into the release system. +If some of the changes conflict, +get will print an error; +the generated result +should be carefully examined +before the delta is made. +.sh 2 "A more detailed example" +.pp +The following technique might be used +to maintain a different version of a program. +First, +create a directory to contain the new version: +.(b +mkdir ../newxyz +cd ../newxyz +.)b +Edit a copy of the program +on a branch: +.(b +sccs \-d../xyz edit prog.c +.)b +When using the old version, +be sure to use the +.b \-b +flag to info, check, tell, and clean +to avoid confusion. +For example, use: +.(b +sccs info \-b +.)b +when in the directory +.q xyz . +.pp +If you want to save a copy of the program +(still on the branch) +back in the s-file, +you can use: +.(b +sccs -d../xyz deledit prog.c +.)b +which will do a delta on the branch +and reedit it for you. +.pp +When the experiment is complete, merge it back into the s-file +using delta: +.(b +sccs -d../xyz delta prog.c +.)b +At this point you must decide whether this version +should be merged back into the trunk +(\c +.i i.e. +the default version), +which may have undergone changes. +If so, it can be merged using the +.b \-i +flag to +.i edit +as described above. +.sh 2 "A warning" +.pp +Branches should be kept to a minimum. +After the first branch from the trunk, +\*I's are assigned rather haphazardly, +and the structure gets complex fast. +.sh 1 "Using \*S with Make" +.pp +\*S and make can be made to work together +with a little care. +A few sample makefiles +for common applications are shown. +.pp +There are a few basic entries that every makefile +ought to have. +These are: +.nr ii 1i +.ip a.out +(or whatever the makefile generates.) +This entry regenerates whatever this makefile is +supposed to regenerate. +If the makefile regenerates many things, +this should be called +.q all +and should in turn +have dependencies on everything +the makefile can generate. +.ip install +Moves the objects to the final +resting place, +doing any special +.i chmod 's +or +.i ranlib 's +as appropriate. +.ip sources +Creates all the source files from \*S files. +.ip clean +Removes all files from the current directory +that can be regenerated from \*S files. +.ip print +Prints the contents of the directory. +.lp +The examples shown below are only partial examples, +and may omit some of these entries +when they are deemed to be obvious. +.pp +The +.i clean +entry should not remove files that can be +regenerated from the \*S files. +It is sufficiently important to have the +source files around at all times +that the only time they should be removed +is when the directory is being mothballed. +To do this, the command: +.(b +sccs clean +.)b +can be used. +This will remove all files for which an s-file +exists, +but which is not being edited. +.sh 2 "To maintain single programs" +.pp +Frequently there are directories with several +largely unrelated programs +(such as simple commands). +These can be put into a single makefile: +.(b +LDFLAGS= \-i \-s +.sp \n(psu +prog: prog.o + $(CC) $(LDFLAGS) \-o prog prog.o +prog.o: prog.c prog.h +.sp \n(psu +example: example.o + $(CC) $(LDFLAGS) \-o example example.o +example.o: example.c +.sp \n(psu +\&.DEFAULT: + sccs get $< +.)b +The trick here +is that the .DEFAULT rule +is called every time +something is needed +that does not exist, +and no other rule exists to make it. +The explicit dependency of the +.b \&.o +file on the +.b \&.c +file is important. +Another way of doing the same thing is: +.(b +SRCS= prog.c prog.h example.c +.sp \n(psu +LDFLAGS= \-i \-s +.sp \n(psu +prog: prog.o + $(CC) $(LDFLAGS) \-o prog prog.o +prog.o: prog.h +.sp \n(psu +example: example.o + $(CC) $(LDFLAGS) \-o example example.o +.sp \n(psu +sources: $(SRCS) +$(SRCS): + sccs get $@ +.)b +There are a couple of advantages to this approach: +(1) the explicit dependencies of the .o on the .c files are +not needed, +(2) there is an entry called "sources" so if you want to get +all the sources you can just say +.q "make sources" , +and +(3) the makefile is less likely to do confusing things +since it won't try to +.i get +things that do not exist. +.sh 2 "To maintain a library" +.pp +Libraries that are largely static +are best updated using explicit commands, +since +.i make +doesn't know about updating them properly. +However, +libraries that are in the process of being developed +can be handled quite adequately. +The problem is that the .o files +have to be kept out of the library +as well as in the library. +.(b +# configuration information +OBJS= a.o b.o c.o d.o +SRCS= a.c b.c c.c d.s x.h y.h z.h +TARG= /usr/lib +.sp \n(psu +# programs +GET= sccs get +REL= +AR= \-ar +RANLIB= ranlib +.sp \n(psu +lib.a: $(OBJS) + $(AR) rvu lib.a $(OBJS) + $(RANLIB) lib.a +.sp \n(psu +install: lib.a + sccs check + cp lib.a $(TARG)/lib.a + $(RANLIB) $(TARG)/lib.a +.sp \n(psu +sources: $(SRCS) +$(SRCS): + $(GET) $(REL) $@ +.sp \n(psu +print: sources + pr *.h *.[cs] +clean: + rm \-f *.o + rm \-f core a.out $(LIB) +.)b +.pp +The +.q "$(REL)" +in the get +can be used to get old versions +easily; for example: +.(b +make b.o REL=\-r1.3 +.)b +.pp +The +.i install +entry includes the line +.q "sccs check" +before anything else. +This guarantees that all the s-files +are up to date +(\c +.i i.e. , +nothing is being edited), +and will abort the +.i make +if this condition is not met. +.sh 2 "To maintain a large program" +.(b +OBJS= a.o b.o c.o d.o +SRCS= a.c b.c c.y d.s x.h y.h z.h +.sp \n(psu +GET= sccs get +REL= +.sp \n(psu +a.out: $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) $(LIBS) +.sp \n(psu +sources: $(SRCS) +$(SRCS): + $(GET) $(REL) $@ +.)b +(The +.i print +and +.i clean +entries are identical to the previous case.) +This makefile requires copies of the source and object files +to be kept during development. +It is probably also wise to include lines of the form: +.(b +a.o: x.h y.h +b.o: z.h +c.o: x.h y.h z.h +z.h: x.h +.)b +so that modules will be recompiled +if header files change. +.pp +Since +.i make +does not do transitive closure on dependencies, +you may find in some makefiles lines like: +.(b +z.h: x.h + touch z.h +.)b +This would be used in cases where file z.h +has a line: +.(b +#include "x.h" +.)b +in order to bring the mod date of z.h in line +with the mod date of x.h. +When you have a makefile such as above, +the +.i touch +command can be removed completely; +the equivalent effect will be achieved +by doing an automatic +.i get +on z.h. +.sh 1 "Further Information" +.pp +The +.i "SCCS/PWB User's Manual" +gives a deeper description +of how to use \*S. +Of particular interest +are the numbering of branches, +the l-file, +which gives a description of what deltas were used on a get, +and certain other \*S commands. +.pp +The \*S manual pages +are a good last resort. +These should be read by software managers +and by people who want to know +everything about everything. +.pp +Both of these documents were written without the +.i sccs +front end in mind, +so most of the examples are slightly different from those +in this document. +.bp +.sz 12 +.ce +.b "Quick Reference" +.sz +.sp 2 +.sh 1 Commands 1 +.pp +The following commands should all be preceded with +.q sccs . +This list is not exhaustive; +for more options see +.i "Further Information" . +.ip get 9n +Gets files for compilation (not for editing). +Id keywords are expanded. +.ba 9n +.nr ii 8n +.ip \-r\fI\*I\fP +Version to get. +.ip \-p +Send to standard output rather than to the actual file. +.ip \-k +Don't expand id keywords. +.ip \-i\fIlist\fP +List of deltas to include. +.ip \-x\fIlist\fP +List of deltas to exclude. +.ip \-m +Precede each line with \*I of creating delta. +.ip \-c\fIdate\fP +Don't apply any deltas created after +.i date. +.ba +.ip edit 9n +Gets files for editing. +Id keywords are not expanded. +Should be matched with a +.i delta +command. +.ba 9n +.nr ii 8n +.ip \-r\fI\*I\fP +Same as +.i get . +If +.i \*I +specifies a release that does not yet exist, +the highest numbered delta is retrieved +and the new delta is numbered with +.i \*I . +.ip \-b +Create a branch. +.ip \-i\fIlist\fP +Same as +.i get . +.ip \-x\fIlist\fP +Same as +.i get . +.ba +.ip delta 9n +Merge a file gotten using +.i edit +back into the s-file. +Collect comments about why this delta was made. +.ip unedit 9n +Remove a file that has been edited previously +without merging the changes into the s-file. +.ip prt 9n +Produce a report of changes. +.ba 9n +.nr ii 5n +.ip \-t +Print the descriptive text. +.ip \-e +Print (nearly) everything. +.ba +.ip info 9n +Give a list of all files being edited. +.ba 9n +.nr ii 5n +.ip \-b +Ignore branches. +.ip \-u[\fIuser\fP] +Ignore files not being edited by +.i user . +.ba +.ip check 9n +Same as +.i info , +except that nothing is printed if nothing is being edited +and exit status is returned. +.ip tell 9n +Same as +.i info , +except that one line is produced per file being edited containing +only the file name. +.ip clean 9n +Remove all files that can be regenerated from the +s-file. +.ip what 9n +Find and print id keywords. +.ip admin 9n +Create or set parameters on s-files. +.ba 9n +.nr ii 8n +.ip \-i\fIfile\fP +Create, using +.i file +as the initial contents. +.ip \-z +Rebuild the checksum in case +the file has been trashed. +.ip \-f\fIflag\fP +Turn on the +.i flag . +.ip \-d\fIflag\fP +Turn off (delete) the +.i flag . +.ip \-t\fIfile\fP +Replace the descriptive text +in the s-file with the contents of +.i file . +If +.i file +is omitted, +the text is deleted. +Useful for storing documentation +or +.q "design & implementation" +documents to insure they get distributed with the +s-file. +.lp +Useful flags are: +.ip b +Allow branches to be made using the \-b flag to +.i edit. +.ip d\fI\*I\fP +Default \*I to be used +on a +.i get +or +.i edit . +.ip i +Cause +.q "No Id Keywords" +error message +to be a fatal error rather than a warning. +.ip t +The module +.q type ; +the value of this flag replaces the +.b %\&Y\&% +keyword. +.ba +.ip fix 9n +Remove a delta and reedit it. +.ip delget 9n +Do a +.i delta +followed by a +.i get . +.ip deledit 9n +Do a +.i delta +followed by an +.i edit . +.sh 1 "Id Keywords" +.nr ii 6n +.ip "%\&Z\&%" +Expands to +.q @\&(#) +for the +.i what +command to find. +.ip "%\&M\&%" +The current module name, +.i e.g., +.q prog.c . +.ip "%\&I\&%" +The highest \*I applied. +.ip "%\&W\&%" +A shorthand for +.q "%\&Z\&%%\&M\&% %\&I\&%" . +.ip "%\&G\&%" +The date of the delta +corresponding to the +.q "%\&I\&%" +keyword. +.ip "%\&R\&%" +The current release number, +.i i.e. , +the first component of the +.q "%\&I\&%" +keyword. +.ip "%\&Y\&%" +Replaced by the value of the +.b t +flag +(set by +.i admin ). diff --git a/usr.bin/sccs/PSD.doc/spell.ok b/usr.bin/sccs/PSD.doc/spell.ok new file mode 100644 index 0000000..fb2fe24 --- /dev/null +++ b/usr.bin/sccs/PSD.doc/spell.ok @@ -0,0 +1,77 @@ +AccessSid +Admin +Allman +Berkeley.Edu +Delget +Ingres +LDFLAGS +LIB +LIBS +OBJS +OpsysSid +PS1:14 +PWB +REL +SCCS +SID +SRCS +Sccs +SccsId +System''PS1:14 +TARG +a.c +a.o +a.out +access.h +admin +b.c +b.o +backslash +bi +c.c +c.o +c.y +ch +cm7 +cmd +cs +d.o +d.s +deledit +delget +eric +example.c +example.o +fb +fd1 +foreach +g.c +info +inline +john +lib +lib.a +makefile +makefiles +mod +mothballed +newxyz +ok +opsys.h +prog +prog.c +prog.h +prog.o +prt +rvu +sccs +sccsdiff +src +syssccs +t.c +ujohn +who.c +x.h +xyz +y.h +z.h diff --git a/usr.bin/sccs/pathnames.h b/usr.bin/sccs/pathnames.h new file mode 100644 index 0000000..4da6874 --- /dev/null +++ b/usr.bin/sccs/pathnames.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_SCCSADMIN "/usr/local/bin/admin" +#define _PATH_SCCSBDIFF "/usr/local/bin/bdiff" +#define _PATH_SCCSCOMB "/usr/local/bin/comb" +#define _PATH_SCCSDELTA "/usr/local/bin/delta" +#define _PATH_SCCSDIFF "/usr/local/bin/sccsdiff" +#define _PATH_SCCSGET "/usr/local/bin/get" +#define _PATH_SCCSHELP "/usr/local/bin/help" +#define _PATH_SCCSPRS "/usr/local/bin/prs" +#define _PATH_SCCSPRT "/usr/local/bin/prt" +#define _PATH_SCCSRMDEL "/usr/local/bin/rmdel" +#define _PATH_SCCSVAL "/usr/local/bin/val" +#define _PATH_SCCSWHAT "/usr/local/bin/what" +#undef _PATH_TMP +#define _PATH_TMP "/tmp/sccsXXXXX" diff --git a/usr.bin/sccs/sccs.1 b/usr.bin/sccs/sccs.1 new file mode 100644 index 0000000..7f4990c --- /dev/null +++ b/usr.bin/sccs/sccs.1 @@ -0,0 +1,398 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)sccs.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt SCCS 1 +.Os BSD 4.2 +.Sh NAME +.Nm sccs +.Nd front end for the +.Li SCCS +subsystem +.Sh SYNOPSIS +.Nm sccs +.Op Fl r +.Op Fl d Ar path +.Op Fl p Ar path +.Ar command +.Op flags +.Op Ar +.Sh DESCRIPTION +.Nm Sccs +is a front end to the +.Li SCCS +programs +that +helps them mesh more cleanly +with +the rest of UNIX. +It +also includes the capability to run +.Dq set user id +to another user +to +provide additional protection. +.Pp +Basically, +.Nm sccs +runs the command with the specified +.Ar flags +and +.Ar args . +Each argument is normally modified to be prepended with +.Dq Li SCCS/s. . +.Pp +Flags to be interpreted by the +.Nm sccs +program must be before the +.Ar command +argument. +Flags to be passed to the actual +.Li SCCS +program must come after the +.Ar command +argument. +These flags are specific to the command and +are discussed in the documentation for that command. +.Pp +Besides the usual +.Li SCCS +commands, +several +.Dq pseudo-commands +can be issued. +These are: +.Bl -tag -width deledit +.It Cm edit +Equivalent +to +.Dq Li get \-e . +.It Cm delget +Perform a delta on the named files and +then get new versions. +The new versions will have id keywords expanded, and +will not be editable. +The +.Fl m , +.Fl p , +.Fl r , +.Fl s , +and +.Fl y +flags will be passed to +.Nm delta , +and the +.Fl b, +.Fl c , +.Fl e , +.Fl i , +.Fl k , +.Fl l , +.Fl s , +.\" anybody who has a bad xterm which is almost anyone +and +.Fl x +flags will be passed to get. +.It Cm deledit +Equivalent +to +.Nm delget +except that the +.Nm get +phase includes the +.Fl e +flag. +This +option is useful for making a +.Em checkpoint +of your current editing phase. The same flags will be passed to delta +as described above, and +all the flags listed for +.om get +above except +.Fl e +and +.Fl k +are +passed to +.Nm edit . +.It Cm create +Creates +an +.Li SCCS +file , +taking +the initial contents from the file of the same name. +Any +flags to +.Nm admin +are accepted. If the creation is successful, +the files are renamed with a comma on the front. +These should be removed when you are convinced that the +.Li SCCS +files +have been created successfully. +.It Cm fix +Must +be followed by a +.Fl r +flag. +This command essentially removes the named delta, but +leaves you with a copy of the delta +with the changes that were in it. It +is useful for fixing small compiler bugs, etc. +Since it doesn't leave audit trails, it should be used carefully. +.It Cm clean +This routine removes everything from the current directory +that can be recreated from SCCS files. +It will not remove any files being edited. +If the +.Fl b +flag is given, branches are ignored in the determination of +whether they are being edited; this +is dangerous if you are keeping the branches in the +same directory. +.It Cm unedit +This +is the opposite of an +.Nm edit +or +a +.Dq Li get \-e . +It should be used with extreme caution, since +any changes you made since the get will be irretrievably lost. +.It Cm info +Gives a listing of all files being edited. +If the +.Fl b +flag +is given, branches (i.e., +.Li SID Ns \&\'s +with two or fewer components) +are ignored. If the +.Fl u +flag is given (with an optional argument) then +only files being edited by you (or the named user) are listed. +.It Cm check +Like +.Nm info +except that nothing is printed if nothing is being edited, and +a non-zero exit status is returned if anything is being edited. +The intent is to have this included in an +.Em install +entry in a makefile to insure that everything is included into the +.Li SCCS +file before a version is installed. +.It Cm tell +Gives a newline-separated list of the files being edited +on the standard output. Takes the +.Fl b +and +.Fl u +flags like +.Nm info +and +.Nm check . +.It Cm diffs +Gives a +.Nm diff +listing between the current version of the +program(s) you have out for editing and the versions in +.Li SCCS +format. +The +.Fl r , +.Fl c , +.Fl i , +.Fl x , +and +.Fl t +flags are passed to +.if n \{\ +. br +.\} +.Nm get ; +the +.Fl l , +.Fl s , +.Fl e , +.Fl f , +.Fl h , +and +.Fl b +options are passed to +.if n \{\ +. br +.\} +.Nm diff . +The +.Fl C +flag is passed to +.Nm diff +as +.Fl c . +.It Cm print +This command prints out verbose information +about the named files. +.Pp +.It Fl r +Runs +.Nm sccs +as the real user rather than as whatever effective user +.Nm sccs +is +.Dq Li set user id +to. +.It Fl d +Specifies a root directory for the +.Li SCCS +files. +The default is the current directory. +If environment variable +.Ev PROJECT +is set, +it will be used to determine the +.Fl d +flag. +.It Fl p +Defines the pathname of the directory in which the +.Li SCCS +files will be found; +.Dq Li SCCS +is the default. +The +.Fl p +flag +differs from the +.Fl d +flag +in that the +.Fl d +argument is prepended to the entire pathname and the +.Fl p +argument is inserted before the final component of the pathname. +For example, +.Dq Li sccs \-d/x \-py get a/b +will convert to +.Dq Li get /x/a/y/s.b . +The intent here is to create aliases such as +.Dq Li alias syssccs sccs -d/usr/src +which +will be used as +.Dq Li syssccs get cmd/who.c . +.Pp +Certain +commands (such as +.Nm admin ) +cannot be run +.Dq Li set user id +by all users, since this would allow anyone to change the authorizations. +These commands are always run as the real user. +.Sh EXAMPLES +To get a file for editing, +edit it, +and produce a new delta: +.Pp +.Dl sccs get \-e file.c +.Dl ex file.c +.Dl sccs delta file.c +.Pp +To get a file from another directory: +.Pp +.Dl sccs \-p/usr/src/sccs/s. get cc.c +.Pp +or +.Pp +.Dl sccs get /usr/src/sccs/s.cc.c +.Pp +To make a delta of a large number of files +in the current directory: +.Pp +.Dl sccs delta *.c +.Pp +To get a list of files being edited that are not on branches: +.Pp +.Dl sccs info \-b +.Pp +To delta everything being edited by you: +.Pp +.Dl sccs delta \`sccs tell \-u\` +.Pp +In a makefile, to get source files +from an +.Li SCCS +file if it does not already exist: +.Pp +.Dl SRCS = +.Dl $(SRCS): +.Dl \&\tsccs get $(REL) $@ +.Sh ENVIRONMENT +.Bl -tag -width Ar +.It Ev PROJECT +The PROJECT environment variable is checked by the +.Fl d +flag. If +it begins with a slash, it is taken directly; otherwise, +the home directory of a user of that name is +examined for a subdirectory +.Dq Li src +or +.Dq Li source . +If such a directory is found, it is used. +.El +.Sh SEE ALSO +.Xr what 1 +.Xr admin SCCS , +.Xr chghist SCCS , +.Xr comb SCCS , +.Xr delta SCCS , +.Xr get SCCS , +.Xr help SCCS , +.Xr prt SCCS , +.Xr rmdel SCCS , +.Xr sccsdiff SCCS , +.Rs +.%A Eric Allman +.%T "An Introduction to the Source Code Control System" +.Re +.Sh HISTORY +The +.Nm sccs +command +appeared in +.Bx 4.3 . +.Sh BUGS +It should be able to take directory arguments on pseudo-commands +like the +.Li SCCS +commands do. diff --git a/usr.bin/sccs/sccs.c b/usr.bin/sccs/sccs.c new file mode 100644 index 0000000..2dfd76d --- /dev/null +++ b/usr.bin/sccs/sccs.c @@ -0,0 +1,1621 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)sccs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +/* +** SCCS.C -- human-oriented front end to the SCCS system. +** +** Without trying to add any functionality to speak of, this +** program tries to make SCCS a little more accessible to human +** types. The main thing it does is automatically put the +** string "SCCS/s." on the front of names. Also, it has a +** couple of things that are designed to shorten frequent +** combinations, e.g., "delget" which expands to a "delta" +** and a "get". +** +** This program can also function as a setuid front end. +** To do this, you should copy the source, renaming it to +** whatever you want, e.g., "syssccs". Change any defaults +** in the program (e.g., syssccs might default -d to +** "/usr/src/sys"). Then recompile and put the result +** as setuid to whomever you want. In this mode, sccs +** knows to not run setuid for certain programs in order +** to preserve security, and so forth. +** +** Usage: +** sccs [flags] command [args] +** +** Flags: +** -d represents a directory to search +** out of. It should be a full pathname +** for general usage. E.g., if is +** "/usr/src/sys", then a reference to the +** file "dev/bio.c" becomes a reference to +** "/usr/src/sys/dev/bio.c". +** -p prepends to the final component +** of the pathname. By default, this is +** "SCCS". For example, in the -d example +** above, the path then gets modified to +** "/usr/src/sys/dev/SCCS/s.bio.c". In +** more common usage (without the -d flag), +** "prog.c" would get modified to +** "SCCS/s.prog.c". In both cases, the +** "s." gets automatically prepended. +** -r run as the real user. +** +** Commands: +** admin, +** get, +** delta, +** rmdel, +** cdc, +** etc. Straight out of SCCS; only difference +** is that pathnames get modified as +** described above. +** enter Front end doing "sccs admin -i " +** create Macro for "enter" followed by "get". +** edit Macro for "get -e". +** unedit Removes a file being edited, knowing +** about p-files, etc. +** delget Macro for "delta" followed by "get". +** deledit Macro for "delta" followed by "get -e". +** branch Macro for "get -b -e", followed by "delta +** -s -n", followd by "get -e -t -g". +** diffs "diff" the specified version of files +** and the checked-out version. +** print Macro for "prs -e" followed by "get -p -m". +** tell List what files are being edited. +** info Print information about files being edited. +** clean Remove all files that can be +** regenerated from SCCS files. +** check Like info, but return exit status, for +** use in makefiles. +** fix Remove a top delta & reedit, but save +** the previous changes in that delta. +** +** Compilation Flags: +** UIDUSER -- determine who the user is by looking at the +** uid rather than the login name -- for machines +** where SCCS gets the user in this way. +** SCCSDIR -- if defined, forces the -d flag to take on +** this value. This is so that the setuid +** aspects of this program cannot be abused. +** This flag also disables the -p flag. +** SCCSPATH -- the default for the -p flag. +** MYNAME -- the title this program should print when it +** gives error messages. +** +** Compilation Instructions: +** cc -O -n -s sccs.c +** The flags listed above can be -D defined to simplify +** recompilation for variant versions. +** +** Author: +** Eric Allman, UCB/INGRES +** Copyright 1980 Regents of the University of California +*/ + + +/******************* Configuration Information ********************/ + +# ifndef SCCSPATH +# define SCCSPATH "SCCS" /* pathname in which to find s-files */ +# endif NOT SCCSPATH + +# ifndef MYNAME +# define MYNAME "sccs" /* name used for printing errors */ +# endif NOT MYNAME + +/**************** End of Configuration Information ****************/ + +typedef char bool; +# define TRUE 1 +# define FALSE 0 + +# define bitset(bit, word) ((bool) ((bit) & (word))) + +struct sccsprog +{ + char *sccsname; /* name of SCCS routine */ + short sccsoper; /* opcode, see below */ + short sccsflags; /* flags, see below */ + char *sccspath; /* pathname of binary implementing */ +}; + +/* values for sccsoper */ +# define PROG 0 /* call a program */ +# define CMACRO 1 /* command substitution macro */ +# define FIX 2 /* fix a delta */ +# define CLEAN 3 /* clean out recreatable files */ +# define UNEDIT 4 /* unedit a file */ +# define SHELL 5 /* call a shell file (like PROG) */ +# define DIFFS 6 /* diff between sccs & file out */ +# define DODIFF 7 /* internal call to diff program */ +# define ENTER 8 /* enter new files */ + +/* bits for sccsflags */ +# define NO_SDOT 0001 /* no s. on front of args */ +# define REALUSER 0002 /* protected (e.g., admin) */ + +/* modes for the "clean", "info", "check" ops */ +# define CLEANC 0 /* clean command */ +# define INFOC 1 /* info command */ +# define CHECKC 2 /* check command */ +# define TELLC 3 /* give list of files being edited */ + +/* +** Description of commands known to this program. +** First argument puts the command into a class. Second arg is +** info regarding treatment of this command. Third arg is a +** list of flags this command accepts from macros, etc. Fourth +** arg is the pathname of the implementing program, or the +** macro definition, or the arg to a sub-algorithm. +*/ + +struct sccsprog SccsProg[] = { + "admin", PROG, REALUSER, _PATH_SCCSADMIN, + "cdc", PROG, 0, _PATH_SCCSRMDEL, + "comb", PROG, 0, _PATH_SCCSCOMB, + "delta", PROG, 0, _PATH_SCCSDELTA, + "get", PROG, 0, _PATH_SCCSGET, + "help", PROG, NO_SDOT, _PATH_SCCSHELP, + "prs", PROG, 0, _PATH_SCCSPRS, + "prt", PROG, 0, _PATH_SCCSPRT, + "rmdel", PROG, REALUSER, _PATH_SCCSRMDEL, + "val", PROG, 0, _PATH_SCCSVAL, + "what", PROG, NO_SDOT, _PATH_SCCSWHAT, + "sccsdiff", SHELL, REALUSER, _PATH_SCCSDIFF, + "edit", CMACRO, NO_SDOT, "get -e", + "delget", CMACRO, NO_SDOT, "delta:mysrp/get:ixbeskcl -t", + "deledit", CMACRO, NO_SDOT, + "delta:mysrp -n/get:ixbskcl -e -t -g", + "fix", FIX, NO_SDOT, NULL, + "clean", CLEAN, REALUSER|NO_SDOT, + (char *) CLEANC, + "info", CLEAN, REALUSER|NO_SDOT, + (char *) INFOC, + "check", CLEAN, REALUSER|NO_SDOT, + (char *) CHECKC, + "tell", CLEAN, REALUSER|NO_SDOT, + (char *) TELLC, + "unedit", UNEDIT, NO_SDOT, NULL, + "diffs", DIFFS, NO_SDOT|REALUSER, + NULL, + "-diff", DODIFF, NO_SDOT|REALUSER, + _PATH_SCCSBDIFF, + "print", CMACRO, 0, "prs -e/get -p -m -s", + "branch", CMACRO, NO_SDOT, + "get:ixrc -e -b/delta: -s -n -ybranch-place-holder/get:pl -e -t -g", + "enter", ENTER, NO_SDOT, NULL, + "create", CMACRO, NO_SDOT, "enter/get:ixbeskcl -t", + NULL, -1, 0, NULL +}; + +/* one line from a p-file */ +struct pfile +{ + char *p_osid; /* old SID */ + char *p_nsid; /* new SID */ + char *p_user; /* user who did edit */ + char *p_date; /* date of get */ + char *p_time; /* time of get */ + char *p_aux; /* extra info at end */ +}; + +char *SccsPath = SCCSPATH; /* pathname of SCCS files */ +# ifdef SCCSDIR +char *SccsDir = SCCSDIR; /* directory to begin search from */ +# else +char *SccsDir = ""; +# endif +char MyName[] = MYNAME; /* name used in messages */ +int OutFile = -1; /* override output file for commands */ +bool RealUser; /* if set, running as real user */ +# ifdef DEBUG +bool Debug; /* turn on tracing */ +# endif +# ifndef V6 +extern char *getenv(); +# endif V6 + +char *gstrcat(), *strcat(); +char *gstrncat(), *strncat(); +char *gstrcpy(), *strcpy(); +#define FBUFSIZ BUFSIZ +#define PFILELG 120 + +main(argc, argv) + int argc; + char **argv; +{ + register char *p; + extern struct sccsprog *lookup(); + register int i; +# ifndef V6 +# ifndef SCCSDIR + register struct passwd *pw; + extern struct passwd *getpwnam(); + char buf[FBUFSIZ]; + + /* pull "SccsDir" out of the environment (possibly) */ + p = getenv("PROJECTDIR"); + if (p != NULL && p[0] != '\0') + { + if (p[0] == '/') + SccsDir = p; + else + { + pw = getpwnam(p); + if (pw == NULL) + { + usrerr("user %s does not exist", p); + exit(EX_USAGE); + } + gstrcpy(buf, pw->pw_dir, sizeof(buf)); + gstrcat(buf, "/src", sizeof(buf)); + if (access(buf, 0) < 0) + { + gstrcpy(buf, pw->pw_dir, sizeof(buf)); + gstrcat(buf, "/source", sizeof(buf)); + if (access(buf, 0) < 0) + { + usrerr("project %s has no source!", p); + exit(EX_USAGE); + } + } + SccsDir = buf; + } + } +# endif SCCSDIR +# endif V6 + + /* + ** Detect and decode flags intended for this program. + */ + + if (argc < 2) + { + fprintf(stderr, "Usage: %s [flags] command [flags]\n", MyName); + exit(EX_USAGE); + } + argv[argc] = NULL; + + if (lookup(argv[0]) == NULL) + { + while ((p = *++argv) != NULL) + { + if (*p != '-') + break; + switch (*++p) + { + case 'r': /* run as real user */ + setuid(getuid()); + RealUser++; + break; + +# ifndef SCCSDIR + case 'p': /* path of sccs files */ + SccsPath = ++p; + if (SccsPath[0] == '\0' && argv[1] != NULL) + SccsPath = *++argv; + break; + + case 'd': /* directory to search from */ + SccsDir = ++p; + if (SccsDir[0] == '\0' && argv[1] != NULL) + SccsDir = *++argv; + break; +# endif + +# ifdef DEBUG + case 'T': /* trace */ + Debug++; + break; +# endif + + default: + usrerr("unknown option -%s", p); + break; + } + } + if (SccsPath[0] == '\0') + SccsPath = "."; + } + + i = command(argv, FALSE, ""); + exit(i); +} + +/* +** COMMAND -- look up and perform a command +** +** This routine is the guts of this program. Given an +** argument vector, it looks up the "command" (argv[0]) +** in the configuration table and does the necessary stuff. +** +** Parameters: +** argv -- an argument vector to process. +** forkflag -- if set, fork before executing the command. +** editflag -- if set, only include flags listed in the +** sccsklets field of the command descriptor. +** arg0 -- a space-seperated list of arguments to insert +** before argv. +** +** Returns: +** zero -- command executed ok. +** else -- error status. +** +** Side Effects: +** none. +*/ + +command(argv, forkflag, arg0) + char **argv; + bool forkflag; + char *arg0; +{ + register struct sccsprog *cmd; + register char *p; + char buf[FBUFSIZ]; + extern struct sccsprog *lookup(); + char *nav[1000]; + char **np; + register char **ap; + register int i; + register char *q; + extern bool unedit(); + int rval = 0; + extern char *index(); + extern char *makefile(); + char *editchs; + extern char *tail(); + +# ifdef DEBUG + if (Debug) + { + printf("command:\n\t\"%s\"\n", arg0); + for (np = argv; *np != NULL; np++) + printf("\t\"%s\"\n", *np); + } +# endif + + /* + ** Copy arguments. + ** Copy from arg0 & if necessary at most one arg + ** from argv[0]. + */ + + np = ap = &nav[1]; + editchs = NULL; + for (p = arg0, q = buf; *p != '\0' && *p != '/'; ) + { + *np++ = q; + while (*p == ' ') + p++; + while (*p != ' ' && *p != '\0' && *p != '/' && *p != ':') + *q++ = *p++; + *q++ = '\0'; + if (*p == ':') + { + editchs = q; + while (*++p != '\0' && *p != '/' && *p != ' ') + *q++ = *p; + *q++ = '\0'; + } + } + *np = NULL; + if (*ap == NULL) + *np++ = *argv++; + + /* + ** Look up command. + ** At this point, *ap is the command name. + */ + + cmd = lookup(*ap); + if (cmd == NULL) + { + usrerr("Unknown command \"%s\"", *ap); + return (EX_USAGE); + } + + /* + ** Copy remaining arguments doing editing as appropriate. + */ + + for (; *argv != NULL; argv++) + { + p = *argv; + if (*p == '-') + { + if (p[1] == '\0' || editchs == NULL || index(editchs, p[1]) != NULL) + *np++ = p; + } + else + { + if (!bitset(NO_SDOT, cmd->sccsflags)) + p = makefile(p); + if (p != NULL) + *np++ = p; + } + } + *np = NULL; + + /* + ** Interpret operation associated with this command. + */ + + switch (cmd->sccsoper) + { + case SHELL: /* call a shell file */ + *ap = cmd->sccspath; + *--ap = "sh"; + rval = callprog(_PATH_BSHELL, cmd->sccsflags, ap, forkflag); + break; + + case PROG: /* call an sccs prog */ + rval = callprog(cmd->sccspath, cmd->sccsflags, ap, forkflag); + break; + + case CMACRO: /* command macro */ + /* step through & execute each part of the macro */ + for (p = cmd->sccspath; *p != '\0'; p++) + { + q = p; + while (*p != '\0' && *p != '/') + p++; + rval = command(&ap[1], *p != '\0', q); + if (rval != 0) + break; + } + break; + + case FIX: /* fix a delta */ + if (ap[1]==0 || strncmp(ap[1], "-r", 2)!=0) + { + usrerr("-r flag needed for fix command"); + rval = EX_USAGE; + break; + } + + /* get the version with all changes */ + rval = command(&ap[1], TRUE, "get -k"); + + /* now remove that version from the s-file */ + if (rval == 0) + rval = command(&ap[1], TRUE, "rmdel:r"); + + /* and edit the old version (but don't clobber new vers) */ + if (rval == 0) + rval = command(&ap[2], FALSE, "get -e -g"); + break; + + case CLEAN: + rval = clean((int) cmd->sccspath, ap); + break; + + case UNEDIT: + for (argv = np = &ap[1]; *argv != NULL; argv++) + { + if (unedit(*argv)) + *np++ = *argv; + } + *np = NULL; + + /* get all the files that we unedited successfully */ + if (np > &ap[1]) + rval = command(&ap[1], FALSE, "get"); + break; + + case DIFFS: /* diff between s-file & edit file */ + /* find the end of the flag arguments */ + for (np = &ap[1]; *np != NULL && **np == '-'; np++) + continue; + argv = np; + + /* for each file, do the diff */ + p = argv[1]; + while (*np != NULL) + { + /* messy, but we need a null terminated argv */ + *argv = *np++; + argv[1] = NULL; + i = dodiff(ap, tail(*argv)); + if (rval == 0) + rval = i; + argv[1] = p; + } + break; + + case DODIFF: /* internal diff call */ + setuid(getuid()); + for (np = ap; *np != NULL; np++) + { + if ((*np)[0] == '-' && (*np)[1] == 'C') + (*np)[1] = 'c'; + } + + /* insert "-" argument */ + np[1] = NULL; + np[0] = np[-1]; + np[-1] = "-"; + + /* execute the diff program of choice */ +# ifndef V6 + execvp("diff", ap); +# endif + execv(cmd->sccspath, argv); + syserr("cannot exec %s", cmd->sccspath); + exit(EX_OSERR); + + case ENTER: /* enter new sccs files */ + /* skip over flag arguments */ + for (np = &ap[1]; *np != NULL && **np == '-'; np++) + continue; + argv = np; + + /* do an admin for each file */ + p = argv[1]; + while (*np != NULL) + { + printf("\n%s:\n", *np); + strcpy(buf, "-i"); + gstrcat(buf, *np, sizeof(buf)); + ap[0] = buf; + argv[0] = tail(*np); + argv[1] = NULL; + rval = command(ap, TRUE, "admin"); + argv[1] = p; + if (rval == 0) + { + strcpy(buf, ","); + gstrcat(buf, tail(*np), sizeof(buf)); + if (link(*np, buf) >= 0) + unlink(*np); + } + np++; + } + break; + + default: + syserr("oper %d", cmd->sccsoper); + exit(EX_SOFTWARE); + } +# ifdef DEBUG + if (Debug) + printf("command: rval=%d\n", rval); +# endif + return (rval); +} + +/* +** LOOKUP -- look up an SCCS command name. +** +** Parameters: +** name -- the name of the command to look up. +** +** Returns: +** ptr to command descriptor for this command. +** NULL if no such entry. +** +** Side Effects: +** none. +*/ + +struct sccsprog * +lookup(name) + char *name; +{ + register struct sccsprog *cmd; + + for (cmd = SccsProg; cmd->sccsname != NULL; cmd++) + { + if (strcmp(cmd->sccsname, name) == 0) + return (cmd); + } + return (NULL); +} + +/* +** CALLPROG -- call a program +** +** Used to call the SCCS programs. +** +** Parameters: +** progpath -- pathname of the program to call. +** flags -- status flags from the command descriptors. +** argv -- an argument vector to pass to the program. +** forkflag -- if true, fork before calling, else just +** exec. +** +** Returns: +** The exit status of the program. +** Nothing if forkflag == FALSE. +** +** Side Effects: +** Can exit if forkflag == FALSE. +*/ + +callprog(progpath, flags, argv, forkflag) + char *progpath; + short flags; + char **argv; + bool forkflag; +{ + register int i; + register int wpid; + auto int st; + register int sigcode; + register int coredumped; + register const char *sigmsg; + char sigmsgbuf[10+1]; /* "Signal 127" + terminating '\0' */ + +# ifdef DEBUG + if (Debug) + { + printf("callprog:\n"); + for (i = 0; argv[i] != NULL; i++) + printf("\t\"%s\"\n", argv[i]); + } +# endif + + if (*argv == NULL) + return (-1); + + /* + ** Fork if appropriate. + */ + + if (forkflag) + { +# ifdef DEBUG + if (Debug) + printf("Forking\n"); +# endif + i = fork(); + if (i < 0) + { + syserr("cannot fork"); + exit(EX_OSERR); + } + else if (i > 0) + { + while ((wpid = wait(&st)) != -1 && wpid != i) + ; + if ((sigcode = st & 0377) == 0) + st = (st >> 8) & 0377; + else + { + coredumped = sigcode & 0200; + sigcode &= 0177; + if (sigcode != SIGINT && sigcode != SIGPIPE) + { + if (sigcode < NSIG) + sigmsg = sys_siglist[sigcode]; + else + { + sprintf(sigmsgbuf, "Signal %d", + sigcode); + sigmsg = sigmsgbuf; + } + fprintf(stderr, "sccs: %s: %s%s", argv[0], + sigmsg, + coredumped ? " - core dumped": ""); + } + st = EX_SOFTWARE; + } + if (OutFile >= 0) + { + close(OutFile); + OutFile = -1; + } + return (st); + } + } + else if (OutFile >= 0) + { + syserr("callprog: setting stdout w/o forking"); + exit(EX_SOFTWARE); + } + + /* set protection as appropriate */ + if (bitset(REALUSER, flags)) + setuid(getuid()); + + /* change standard input & output if needed */ + if (OutFile >= 0) + { + close(1); + dup(OutFile); + close(OutFile); + } + + /* call real SCCS program */ + execv(progpath, argv); + syserr("cannot execute %s", progpath); + exit(EX_UNAVAILABLE); + /*NOTREACHED*/ +} + +/* +** MAKEFILE -- make filename of SCCS file +** +** If the name passed is already the name of an SCCS file, +** just return it. Otherwise, munge the name into the name +** of the actual SCCS file. +** +** There are cases when it is not clear what you want to +** do. For example, if SccsPath is an absolute pathname +** and the name given is also an absolute pathname, we go +** for SccsPath (& only use the last component of the name +** passed) -- this is important for security reasons (if +** sccs is being used as a setuid front end), but not +** particularly intuitive. +** +** Parameters: +** name -- the file name to be munged. +** +** Returns: +** The pathname of the sccs file. +** NULL on error. +** +** Side Effects: +** none. +*/ + +char * +makefile(name) + char *name; +{ + register char *p; + char buf[3*FBUFSIZ]; + extern char *malloc(); + extern char *rindex(); + extern bool safepath(); + extern bool isdir(); + register char *q; + + p = rindex(name, '/'); + if (p == NULL) + p = name; + else + p++; + + /* + ** Check to see that the path is "safe", i.e., that we + ** are not letting some nasty person use the setuid part + ** of this program to look at or munge some presumably + ** hidden files. + */ + + if (SccsDir[0] == '/' && !safepath(name)) + return (NULL); + + /* + ** Create the base pathname. + */ + + /* first the directory part */ + if (SccsDir[0] != '\0' && name[0] != '/' && strncmp(name, "./", 2) != 0) + { + gstrcpy(buf, SccsDir, sizeof(buf)); + gstrcat(buf, "/", sizeof(buf)); + } + else + gstrcpy(buf, "", sizeof(buf)); + + /* then the head of the pathname */ + gstrncat(buf, name, p - name, sizeof(buf)); + q = &buf[strlen(buf)]; + + /* now copy the final part of the name, in case useful */ + gstrcpy(q, p, sizeof(buf)); + + /* so is it useful? */ + if (strncmp(p, "s.", 2) != 0 && !isdir(buf)) + { + /* sorry, no; copy the SCCS pathname & the "s." */ + gstrcpy(q, SccsPath, sizeof(buf)); + gstrcat(buf, "/s.", sizeof(buf)); + + /* and now the end of the name */ + gstrcat(buf, p, sizeof(buf)); + } + + /* if i haven't changed it, why did I do all this? */ + if (strcmp(buf, name) == 0) + p = name; + else + { + /* but if I have, squirrel it away */ + p = malloc(strlen(buf) + 1); + if (p == NULL) + { + perror("Sccs: no mem"); + exit(EX_OSERR); + } + strcpy(p, buf); + } + + return (p); +} + +/* +** ISDIR -- return true if the argument is a directory. +** +** Parameters: +** name -- the pathname of the file to check. +** +** Returns: +** TRUE if 'name' is a directory, FALSE otherwise. +** +** Side Effects: +** none. +*/ + +bool +isdir(name) + char *name; +{ + struct stat stbuf; + + return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR); +} + +/* +** SAFEPATH -- determine whether a pathname is "safe" +** +** "Safe" pathnames only allow you to get deeper into the +** directory structure, i.e., full pathnames and ".." are +** not allowed. +** +** Parameters: +** p -- the name to check. +** +** Returns: +** TRUE -- if the path is safe. +** FALSE -- if the path is not safe. +** +** Side Effects: +** Prints a message if the path is not safe. +*/ + +bool +safepath(p) + register char *p; +{ + extern char *index(); + + if (*p != '/') + { + while (strncmp(p, "../", 3) != 0 && strcmp(p, "..") != 0) + { + p = index(p, '/'); + if (p == NULL) + return (TRUE); + p++; + } + } + + printf("You may not use full pathnames or \"..\"\n"); + return (FALSE); +} + +/* +** CLEAN -- clean out recreatable files +** +** Any file for which an "s." file exists but no "p." file +** exists in the current directory is purged. +** +** Parameters: +** mode -- tells whether this came from a "clean", "info", or +** "check" command. +** argv -- the rest of the argument vector. +** +** Returns: +** none. +** +** Side Effects: +** Removes files in the current directory. +** Prints information regarding files being edited. +** Exits if a "check" command. +*/ + +clean(mode, argv) + int mode; + char **argv; +{ + struct direct *dir; + char buf[FBUFSIZ]; + char *bufend; + register DIR *dirp; + register char *basefile; + bool gotedit; + bool gotpfent; + FILE *pfp; + bool nobranch = FALSE; + extern struct pfile *getpfent(); + register struct pfile *pf; + register char **ap; + extern char *username(); + char *usernm = NULL; + char *subdir = NULL; + char *cmdname; + + /* + ** Process the argv + */ + + cmdname = *argv; + for (ap = argv; *++ap != NULL; ) + { + if (**ap == '-') + { + /* we have a flag */ + switch ((*ap)[1]) + { + case 'b': + nobranch = TRUE; + break; + + case 'u': + if ((*ap)[2] != '\0') + usernm = &(*ap)[2]; + else if (ap[1] != NULL && ap[1][0] != '-') + usernm = *++ap; + else + usernm = username(); + break; + } + } + else + { + if (subdir != NULL) + usrerr("too many args"); + else + subdir = *ap; + } + } + + /* + ** Find and open the SCCS directory. + */ + + gstrcpy(buf, SccsDir, sizeof(buf)); + if (buf[0] != '\0') + gstrcat(buf, "/", sizeof(buf)); + if (subdir != NULL) + { + gstrcat(buf, subdir, sizeof(buf)); + gstrcat(buf, "/", sizeof(buf)); + } + gstrcat(buf, SccsPath, sizeof(buf)); + bufend = &buf[strlen(buf)]; + + dirp = opendir(buf); + if (dirp == NULL) + { + usrerr("cannot open %s", buf); + return (EX_NOINPUT); + } + + /* + ** Scan the SCCS directory looking for s. files. + ** gotedit tells whether we have tried to clean any + ** files that are being edited. + */ + + gotedit = FALSE; + while (dir = readdir(dirp)) { + if (strncmp(dir->d_name, "s.", 2) != 0) + continue; + + /* got an s. file -- see if the p. file exists */ + gstrcpy(bufend, "/p.", sizeof(buf)); + basefile = bufend + 3; + gstrcpy(basefile, &dir->d_name[2], sizeof(buf)); + + /* + ** open and scan the p-file. + ** 'gotpfent' tells if we have found a valid p-file + ** entry. + */ + + pfp = fopen(buf, "r"); + gotpfent = FALSE; + if (pfp != NULL) + { + /* the file exists -- report it's contents */ + while ((pf = getpfent(pfp)) != NULL) + { + if (nobranch && isbranch(pf->p_nsid)) + continue; + if (usernm != NULL && strcmp(usernm, pf->p_user) != 0 && mode != CLEANC) + continue; + gotedit = TRUE; + gotpfent = TRUE; + if (mode == TELLC) + { + printf("%s\n", basefile); + break; + } + printf("%12s: being edited: ", basefile); + putpfent(pf, stdout); + } + fclose(pfp); + } + + /* the s. file exists and no p. file exists -- unlink the g-file */ + if (mode == CLEANC && !gotpfent) + { + char unlinkbuf[FBUFSIZ]; + gstrcpy(unlinkbuf, &dir->d_name[2], sizeof(unlinkbuf)); + unlink(unlinkbuf); + } + } + + /* cleanup & report results */ + closedir(dirp); + if (!gotedit && mode == INFOC) + { + printf("Nothing being edited"); + if (nobranch) + printf(" (on trunk)"); + if (usernm == NULL) + printf("\n"); + else + printf(" by %s\n", usernm); + } + if (mode == CHECKC) + exit(gotedit); + return (EX_OK); +} + +/* +** ISBRANCH -- is the SID a branch? +** +** Parameters: +** sid -- the sid to check. +** +** Returns: +** TRUE if the sid represents a branch. +** FALSE otherwise. +** +** Side Effects: +** none. +*/ + +isbranch(sid) + char *sid; +{ + register char *p; + int dots; + + dots = 0; + for (p = sid; *p != '\0'; p++) + { + if (*p == '.') + dots++; + if (dots > 1) + return (TRUE); + } + return (FALSE); +} + +/* +** UNEDIT -- unedit a file +** +** Checks to see that the current user is actually editting +** the file and arranges that s/he is not editting it. +** +** Parameters: +** fn -- the name of the file to be unedited. +** +** Returns: +** TRUE -- if the file was successfully unedited. +** FALSE -- if the file was not unedited for some +** reason. +** +** Side Effects: +** fn is removed +** entries are removed from pfile. +*/ + +bool +unedit(fn) + char *fn; +{ + register FILE *pfp; + char *cp, *pfn; + static char tfn[] = _PATH_TMP; + FILE *tfp; + register char *q; + bool delete = FALSE; + bool others = FALSE; + char *myname; + extern char *username(); + struct pfile *pent; + extern struct pfile *getpfent(); + char buf[PFILELG]; + extern char *makefile(), *rindex(), *tail(); + + /* make "s." filename & find the trailing component */ + pfn = makefile(fn); + if (pfn == NULL) + return (FALSE); + q = rindex(pfn, '/'); + if (q == NULL) + q = &pfn[-1]; + if (q[1] != 's' || q[2] != '.') + { + usrerr("bad file name \"%s\"", fn); + return (FALSE); + } + + /* turn "s." into "p." & try to open it */ + *++q = 'p'; + + pfp = fopen(pfn, "r"); + if (pfp == NULL) + { + printf("%12s: not being edited\n", fn); + return (FALSE); + } + + /* create temp file for editing p-file */ + mktemp(tfn); + tfp = fopen(tfn, "w"); + if (tfp == NULL) + { + usrerr("cannot create \"%s\"", tfn); + exit(EX_OSERR); + } + + /* figure out who I am */ + myname = username(); + + /* + ** Copy p-file to temp file, doing deletions as needed. + */ + + while ((pent = getpfent(pfp)) != NULL) + { + if (strcmp(pent->p_user, myname) == 0) + { + /* a match */ + delete++; + } + else + { + /* output it again */ + putpfent(pent, tfp); + others++; + } + } + + /* + * Before changing anything, make sure we can remove + * the file in question (assuming it exists). + */ + if (delete) { + extern int errno; + + cp = tail(fn); + errno = 0; + if (access(cp, 0) < 0 && errno != ENOENT) + goto bad; + if (errno == 0) + /* + * This is wrong, but the rest of the program + * has built in assumptions about "." as well, + * so why make unedit a special case? + */ + if (access(".", 2) < 0) { + bad: + printf("%12s: can't remove\n", cp); + fclose(tfp); + fclose(pfp); + unlink(tfn); + return (FALSE); + } + } + /* do final cleanup */ + if (others) + { + /* copy it back (perhaps it should be linked?) */ + if (freopen(tfn, "r", tfp) == NULL) + { + syserr("cannot reopen \"%s\"", tfn); + exit(EX_OSERR); + } + if (freopen(pfn, "w", pfp) == NULL) + { + usrerr("cannot create \"%s\"", pfn); + return (FALSE); + } + while (fgets(buf, sizeof buf, tfp) != NULL) + fputs(buf, pfp); + } + else + { + /* it's empty -- remove it */ + unlink(pfn); + } + fclose(tfp); + fclose(pfp); + unlink(tfn); + + /* actually remove the g-file */ + if (delete) + { + /* + * Since we've checked above, we can + * use the return from unlink to + * determine if the file existed or not. + */ + if (unlink(cp) >= 0) + printf("%12s: removed\n", cp); + return (TRUE); + } + else + { + printf("%12s: not being edited by you\n", fn); + return (FALSE); + } +} + +/* +** DODIFF -- diff an s-file against a g-file +** +** Parameters: +** getv -- argv for the 'get' command. +** gfile -- name of the g-file to diff against. +** +** Returns: +** Result of get. +** +** Side Effects: +** none. +*/ + +dodiff(getv, gfile) + char **getv; + char *gfile; +{ + int pipev[2]; + int rval; + register int i; + register int pid; + auto int st; + extern int errno; + sig_t osig; + + printf("\n------- %s -------\n", gfile); + fflush(stdout); + + /* create context for diff to run in */ + if (pipe(pipev) < 0) + { + syserr("dodiff: pipe failed"); + exit(EX_OSERR); + } + if ((pid = fork()) < 0) + { + syserr("dodiff: fork failed"); + exit(EX_OSERR); + } + else if (pid > 0) + { + /* in parent; run get */ + OutFile = pipev[1]; + close(pipev[0]); + rval = command(&getv[1], TRUE, "get:rcixt -s -k -p"); + osig = signal(SIGINT, SIG_IGN); + while (((i = wait(&st)) >= 0 && i != pid) || errno == EINTR) + errno = 0; + signal(SIGINT, osig); + /* ignore result of diff */ + } + else + { + /* in child, run diff */ + if (close(pipev[1]) < 0 || close(0) < 0 || + dup(pipev[0]) != 0 || close(pipev[0]) < 0) + { + syserr("dodiff: magic failed"); + exit(EX_OSERR); + } + command(&getv[1], FALSE, "-diff:elsfhbC"); + } + return (rval); +} + +/* +** TAIL -- return tail of filename. +** +** Parameters: +** fn -- the filename. +** +** Returns: +** a pointer to the tail of the filename; e.g., given +** "cmd/ls.c", "ls.c" is returned. +** +** Side Effects: +** none. +*/ + +char * +tail(fn) + register char *fn; +{ + register char *p; + + for (p = fn; *p != 0; p++) + if (*p == '/' && p[1] != '\0' && p[1] != '/') + fn = &p[1]; + return (fn); +} + +/* +** GETPFENT -- get an entry from the p-file +** +** Parameters: +** pfp -- p-file file pointer +** +** Returns: +** pointer to p-file struct for next entry +** NULL on EOF or error +** +** Side Effects: +** Each call wipes out results of previous call. +*/ + +struct pfile * +getpfent(pfp) + FILE *pfp; +{ + static struct pfile ent; + static char buf[PFILELG]; + register char *p; + extern char *nextfield(); + + if (fgets(buf, sizeof buf, pfp) == NULL) + return (NULL); + + ent.p_osid = p = buf; + ent.p_nsid = p = nextfield(p); + ent.p_user = p = nextfield(p); + ent.p_date = p = nextfield(p); + ent.p_time = p = nextfield(p); + ent.p_aux = p = nextfield(p); + + return (&ent); +} + + +char * +nextfield(p) + register char *p; +{ + if (p == NULL || *p == '\0') + return (NULL); + while (*p != ' ' && *p != '\n' && *p != '\0') + p++; + if (*p == '\n' || *p == '\0') + { + *p = '\0'; + return (NULL); + } + *p++ = '\0'; + return (p); +} + /* +** PUTPFENT -- output a p-file entry to a file +** +** Parameters: +** pf -- the p-file entry +** f -- the file to put it on. +** +** Returns: +** none. +** +** Side Effects: +** pf is written onto file f. +*/ + +putpfent(pf, f) + register struct pfile *pf; + register FILE *f; +{ + fprintf(f, "%s %s %s %s %s", pf->p_osid, pf->p_nsid, + pf->p_user, pf->p_date, pf->p_time); + if (pf->p_aux != NULL) + fprintf(f, " %s", pf->p_aux); + else + fprintf(f, "\n"); +} + +/* +** USRERR -- issue user-level error +** +** Parameters: +** f -- format string. +** p1-p3 -- parameters to a printf. +** +** Returns: +** -1 +** +** Side Effects: +** none. +*/ + +/*VARARGS1*/ +usrerr(f, p1, p2, p3) + char *f; +{ + fprintf(stderr, "\n%s: ", MyName); + fprintf(stderr, f, p1, p2, p3); + fprintf(stderr, "\n"); + + return (-1); +} + +/* +** SYSERR -- print system-generated error. +** +** Parameters: +** f -- format string to a printf. +** p1, p2, p3 -- parameters to f. +** +** Returns: +** never. +** +** Side Effects: +** none. +*/ + +/*VARARGS1*/ +syserr(f, p1, p2, p3) + char *f; +{ + extern int errno; + + fprintf(stderr, "\n%s SYSERR: ", MyName); + fprintf(stderr, f, p1, p2, p3); + fprintf(stderr, "\n"); + if (errno == 0) + exit(EX_SOFTWARE); + else + { + perror(NULL); + exit(EX_OSERR); + } +} + /* +** USERNAME -- return name of the current user +** +** Parameters: +** none +** +** Returns: +** name of current user +** +** Side Effects: +** none +*/ + +char * +username() +{ +# ifdef UIDUSER + extern struct passwd *getpwuid(); + register struct passwd *pw; + + pw = getpwuid(getuid()); + if (pw == NULL) + { + syserr("who are you? (uid=%d)", getuid()); + exit(EX_OSERR); + } + return (pw->pw_name); +# else + extern char *getlogin(); + register char *p; + + p = getenv("USER"); + if (p == NULL || p[0] == '\0') + p = getlogin(); + return (p); +# endif UIDUSER +} + +/* +** Guarded string manipulation routines; the last argument +** is the length of the buffer into which the strcpy or strcat +** is to be done. +*/ +char *gstrcat(to, from, length) + char *to, *from; + int length; +{ + if (strlen(from) + strlen(to) >= length) { + gstrbotch(to, from); + } + return(strcat(to, from)); +} + +char *gstrncat(to, from, n, length) + char *to, *from; + int n; + int length; +{ + if (n + strlen(to) >= length) { + gstrbotch(to, from); + } + return(strncat(to, from, n)); +} + +char *gstrcpy(to, from, length) + char *to, *from; + int length; +{ + if (strlen(from) >= length) { + gstrbotch(from, (char *)0); + } + return(strcpy(to, from)); +} +gstrbotch(str1, str2) + char *str1, *str2; +{ + usrerr("Filename(s) too long: %s %s", str1, str2); +} diff --git a/usr.bin/script/Makefile b/usr.bin/script/Makefile new file mode 100644 index 0000000..78dbe68 --- /dev/null +++ b/usr.bin/script/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= script +LDADD= -lutil +DPADD= ${LIBUTIL} + +.include diff --git a/usr.bin/script/script.1 b/usr.bin/script/script.1 new file mode 100644 index 0000000..deda037 --- /dev/null +++ b/usr.bin/script/script.1 @@ -0,0 +1,123 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)script.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt SCRIPT 1 +.Os BSD 4 +.Sh NAME +.Nm script +.Nd make typescript of terminal session +.Sh SYNOPSIS +.Nm script +.Op Fl a +.Op Ar file +.Sh DESCRIPTION +.Nm Script +makes a typescript of everything printed on your terminal. +It is useful for students who need a hardcopy record of an interactive +session as proof of an assignment, as the typescript file +can be printed out later with +.Xr lpr 1 . +.Pp +If the argument +.Ar file +is given, +.Nm +saves all dialogue in +.Ar file . +If no file name is given, the typescript is saved in the file +.Pa typescript . +.Pp +Option: +.Bl -tag -width Ds +.It Fl a +Append the output to +.Ar file +or +.Pa typescript , +retaining the prior contents. +.El +.Pp +The script ends when the forked shell exits (a +.Em control-D +to exit +the Bourne shell +.Pf ( Xr sh 1 ) , +and +.Em exit , +.Em logout +or +.Em control-d +(if +.Em ignoreeof +is not set) for the +C-shell, +.Xr csh 1 ) . +.Pp +Certain interactive commands, such as +.Xr vi 1 , +create garbage in the typescript file. +.Nm Script +works best with commands that do not manipulate the +screen, the results are meant to emulate a hardcopy +terminal. +.Sh ENVIRONMENT +The following environment variable is utilized by +.Nm script : +.Bl -tag -width SHELL +.It Ev SHELL +If the variable +.Ev SHELL +exists, the shell forked by +.Nm script +will be that shell. If +.Ev SHELL +is not set, the Bourne shell +is assumed. (Most shells set this variable automatically). +.El +.Sh SEE ALSO +.Xr csh 1 +(for the +.Em history +mechanism). +.Sh HISTORY +The +.Nm script +command appeared in +.Bx 3.0 . +.Sh BUGS +.Nm Script +places +.Sy everything +in the log file, including linefeeds and backspaces. +This is not what the naive user expects. diff --git a/usr.bin/script/script.c b/usr.bin/script/script.c new file mode 100644 index 0000000..e688d64 --- /dev/null +++ b/usr.bin/script/script.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FILE *fscript; +int master, slave; +int child, subchild; +int outcc; +char *fname; + +struct termios tt; + +__dead void done __P((void)); + void dooutput __P((void)); + void doshell __P((void)); + void err __P((const char *, ...)); + void fail __P((void)); + void finish __P((int)); + void scriptflush __P((int)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int cc; + struct termios rtt; + struct winsize win; + int aflg, ch; + char ibuf[BUFSIZ]; + + aflg = 0; + while ((ch = getopt(argc, argv, "a")) != EOF) + switch(ch) { + case 'a': + aflg = 1; + break; + case '?': + default: + (void)fprintf(stderr, "usage: script [-a] [file]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + if (argc > 0) + fname = argv[0]; + else + fname = "typescript"; + + if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) + err("%s: %s", fname, strerror(errno)); + + (void)tcgetattr(STDIN_FILENO, &tt); + (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win); + if (openpty(&master, &slave, NULL, &tt, &win) == -1) + err("openpty: %s", strerror(errno)); + + (void)printf("Script started, output file is %s\n", fname); + rtt = tt; + cfmakeraw(&rtt); + rtt.c_lflag &= ~ECHO; + (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt); + + (void)signal(SIGCHLD, finish); + child = fork(); + if (child < 0) { + perror("fork"); + fail(); + } + if (child == 0) { + subchild = child = fork(); + if (child < 0) { + perror("fork"); + fail(); + } + if (child) + dooutput(); + else + doshell(); + } + + (void)fclose(fscript); + while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) + (void)write(master, ibuf, cc); + done(); +} + +void +finish(signo) + int signo; +{ + register int die, pid; + union wait status; + + die = 0; + while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0) + if (pid == child) + die = 1; + + if (die) + done(); +} + +void +dooutput() +{ + struct itimerval value; + register int cc; + time_t tvec; + char obuf[BUFSIZ]; + + (void)close(STDIN_FILENO); + tvec = time(NULL); + (void)fprintf(fscript, "Script started on %s", ctime(&tvec)); + + (void)signal(SIGALRM, scriptflush); + value.it_interval.tv_sec = SECSPERMIN / 2; + value.it_interval.tv_usec = 0; + value.it_value = value.it_interval; + (void)setitimer(ITIMER_REAL, &value, NULL); + for (;;) { + cc = read(master, obuf, sizeof (obuf)); + if (cc <= 0) + break; + (void)write(1, obuf, cc); + (void)fwrite(obuf, 1, cc, fscript); + outcc += cc; + } + done(); +} + +void +scriptflush(signo) + int signo; +{ + if (outcc) { + (void)fflush(fscript); + outcc = 0; + } +} + +void +doshell() +{ + char *shell; + + shell = getenv("SHELL"); + if (shell == NULL) + shell = _PATH_BSHELL; + + (void)close(master); + (void)fclose(fscript); + login_tty(slave); + execl(shell, "sh", "-i", NULL); + perror(shell); + fail(); +} + +void +fail() +{ + + (void)kill(0, SIGTERM); + done(); +} + +void +done() +{ + time_t tvec; + + if (subchild) { + tvec = time(NULL); + (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec)); + (void)fclose(fscript); + (void)close(master); + } else { + (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt); + (void)printf("Script done, output file is %s\n", fname); + } + exit(0); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "script: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/sed/Makefile b/usr.bin/sed/Makefile new file mode 100644 index 0000000..99f860b --- /dev/null +++ b/usr.bin/sed/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= sed +SRCS= compile.c main.c misc.c process.c + +.include diff --git a/usr.bin/sed/POSIX b/usr.bin/sed/POSIX new file mode 100644 index 0000000..41955af --- /dev/null +++ b/usr.bin/sed/POSIX @@ -0,0 +1,198 @@ +# @(#)POSIX 8.1 (Berkeley) 6/6/93 + +Comments on the IEEE P1003.2 Draft 12 + Part 2: Shell and Utilities + Section 4.55: sed - Stream editor + +Diomidis Spinellis +Keith Bostic + +In the following paragraphs, "wrong" usually means "inconsistent with +historic practice", as most of the following comments refer to +undocumented inconsistencies between the historical versions of sed and +the POSIX 1003.2 standard. All the comments are notes taken while +implementing a POSIX-compatible version of sed, and should not be +interpreted as official opinions or criticism towards the POSIX committee. +All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2. + + 1. 32V and BSD derived implementations of sed strip the text + arguments of the a, c and i commands of their initial blanks, + i.e. + + #!/bin/sed -f + a\ + foo\ + \ indent\ + bar + + produces: + + foo + indent + bar + + POSIX does not specify this behavior as the System V versions of + sed do not do this stripping. The argument against stripping is + that it is difficult to write sed scripts that have leading blanks + if they are stripped. The argument for stripping is that it is + difficult to write readable sed scripts unless indentation is allowed + and ignored, and leading whitespace is obtainable by entering a + backslash in front of it. This implementation follows the BSD + historic practice. + + 2. Historical versions of sed required that the w flag be the last + flag to an s command as it takes an additional argument. This + is obvious, but not specified in POSIX. + + 3. Historical versions of sed required that whitespace follow a w + flag to an s command. This is not specified in POSIX. This + implementation permits whitespace but does not require it. + + 4. Historical versions of sed permitted any number of whitespace + characters to follow the w command. This is not specified in + POSIX. This implementation permits whitespace but does not + require it. + + 5. The rule for the l command differs from historic practice. Table + 2-15 includes the various ANSI C escape sequences, including \\ + for backslash. Some historical versions of sed displayed two + digit octal numbers, too, not three as specified by POSIX. POSIX + is a cleanup, and is followed by this implementation. + + 6. The POSIX specification for ! does not specify that for a single + command the command must not contain an address specification + whereas the command list can contain address specifications. The + specification for ! implies that "3!/hello/p" works, and it never + has, historically. Note, + + 3!{ + /hello/p + } + + does work. + + 7. POSIX does not specify what happens with consecutive ! commands + (e.g. /foo/!!!p). Historic implementations allow any number of + !'s without changing the behaviour. (It seems logical that each + one might reverse the behaviour.) This implementation follows + historic practice. + + 8. Historic versions of sed permitted commands to be separated + by semi-colons, e.g. 'sed -ne '1p;2p;3q' printed the first + three lines of a file. This is not specified by POSIX. + Note, the ; command separator is not allowed for the commands + a, c, i, w, r, :, b, t, # and at the end of a w flag in the s + command. This implementation follows historic practice and + implements the ; separator. + + 9. Historic versions of sed terminated the script if EOF was reached + during the execution of the 'n' command, i.e.: + + sed -e ' + n + i\ + hello + ' +# +# note -- TWO carriage returns, a peculiarity of sed), this will output the +# sequence of states involved in moving 4 rings, the largest called "a" and +# the smallest called "d", from the first to the second of three towers, so +# that the rings on any tower at any time are in descending order of size. +# You can start with a different arrangement and a different number of rings, +# say :ce:b:ax: and it will give the shortest procedure for moving them all +# to the middle tower. The rules are: the names of the rings must all be +# lower-case letters, they must be input within 3 fields (representing the +# towers) and delimited by 4 colons, such that the letters within each field +# are in alphabetical order (i.e. rings are in descending order of size). +# +# For the benefit of anyone who wants to figure out the script, an "internal" +# line of the form +# b:0abx:1a2b3 :2 :3x2 +# has the following meaning: the material after the three markers :1, :2, +# and :3 represents the three towers; in this case the current set-up is +# ":ab : :x :". The numbers after a, b and x in these fields indicate +# that the next time it gets a chance, it will move a to tower 2, move b +# to tower 3, and move x to tower 2. The string after :0 just keeps track +# of the alphabetical order of the names of the rings. The b at the +# beginning means that it is now dealing with ring b (either about to move +# it, or re-evaluating where it should next be moved to). +# +# Although this version is "limited" to 26 rings because of the size of the +# alphabet, one could write a script using the same idea in which the rings +# were represented by arbitrary [strings][within][brackets], and in place of +# the built-in line of the script giving the order of the letters of the +# alphabet, it would accept from the user a line giving the ordering to be +# assumed, e.g. [ucbvax][decvax][hplabs][foo][bar]. +# +# George Bergman +# Math, UC Berkeley 94720 USA + +# cleaning, diagnostics +s/ *//g +/^$/d +/[^a-z:]/{a\ +Illegal characters: use only a-z and ":". Try again. +d +} +/^:[a-z]*:[a-z]*:[a-z]*:$/!{a\ +Incorrect format: use\ +\ : string1 : string2 : string3 :\ +Try again. +d +} +/\([a-z]\).*\1/{a\ +Repeated letters not allowed. Try again. +d +} +# initial formatting +h +s/[a-z]/ /g +G +s/^:\( *\):\( *\):\( *\):\n:\([a-z]*\):\([a-z]*\):\([a-z]*\):$/:1\4\2\3:2\5\1\3:3\6\1\2:0/ +s/[a-z]/&2/g +s/^/abcdefghijklmnopqrstuvwxyz/ +:a +s/^\(.\).*\1.*/&\1/ +s/.// +/^[^:]/ba +s/\([^0]*\)\(:0.*\)/\2\1:/ +s/^[^0]*0\(.\)/\1&/ +:b +# outputting current state without markers +h +s/.*:1/:/ +s/[123]//gp +g +:c +# establishing destinations +/^\(.\).*\1:1/td +/^\(.\).*:1[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ +/^\(.\).*:1[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ +/^\(.\).*:1[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ +/^\(.\).*:2[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ +/^\(.\).*:2[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ +/^\(.\).*:2[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ +/^\(.\).*:3[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ +/^\(.\).*:3[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ +/^\(.\).*:3[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ +bc +# iterate back to find smallest out-of-place ring +:d +s/^\(.\)\(:0[^:]*\([^:]\)\1.*:\([123]\)[^:]*\1\)\4/\3\2\4/ +td +# move said ring (right, resp. left) +s/^\(.\)\(.*\)\1\([23]\)\(.*:\3[^ ]*\) /\1\2 \4\1\3/ +s/^\(.\)\(.*:\([12]\)[^ ]*\) \(.*\)\1\3/\1\2\1\3\4 / +tb +s/.*/Done! Try another, or end with ^D./p +d diff --git a/usr.bin/sed/TEST/math.sed b/usr.bin/sed/TEST/math.sed new file mode 100644 index 0000000..8e7bf51 --- /dev/null +++ b/usr.bin/sed/TEST/math.sed @@ -0,0 +1,163 @@ +# +# @(#)math.sed 8.1 (Berkeley) 6/6/93 +# +# Addition and multiplication in sed. +# ++ for a limited time only do (expr) too!!! +# +# Kevin S Braunsdorf, PUCC UNIX Group, ksb@cc.purdue.edu. +# +# Ex: +# echo "4+7*3" | sed -f %f + +# make sure the expression is well formed +s/[ ]//g +/[+*\/-]$/{ + a\ + poorly formed expression, operator on the end + q +} +/^[+*\/]/{ + a\ + poorly formed expression, leading operator + q +} + +# fill hold space with done token +x +s/^.*/done/ +x + +# main loop, process operators (*, + and () ) +: loop +/^\+/{ + s/// + b loop +} +/^\(.*\)(\([^)]*\))\(.*\)$/{ + H + s//\2/ + x + s/^\(.*\)\n\(.*\)(\([^()]*\))\(.*\)$/()\2@\4@\1/ + x + b loop +} +/^[0-9]*\*/b mul +/^\([0-9]*\)\+\([0-9+*]*\*[0-9]*\)$/{ + s//\2+\1/ + b loop +} +/^[0-9]*\+/{ + s/$/=/ + b add +} +x +/^done$/{ + x + p + d +} +/^()/{ + s/// + x + G + s/\(.*\)\n\([^@]*\)@\([^@]*\)@\(.*\)/\2\1\3/ + x + s/[^@]*@[^@]*@\(.*\)/\1/ + x + b loop +} +i\ +help, stack problem +p +x +p +q + +# turn mul into add until 1*x -> x +: mul +/^0*1\*/{ + s/// + b loop +} +/^\([0-9]*\)0\*/{ + s/^\([0-9]*\)0\*\([0-9]*\)/\1*\20/ + b mul +} +s/^\([0-9]*\)1\*/\10*/ +s/^\([0-9]*\)2\*/\11*/ +s/^\([0-9]*\)3\*/\12*/ +s/^\([0-9]*\)4\*/\13*/ +s/^\([0-9]*\)5\*/\14*/ +s/^\([0-9]*\)6\*/\15*/ +s/^\([0-9]*\)7\*/\16*/ +s/^\([0-9]*\)8\*/\17*/ +s/^\([0-9]*\)9\*/\18*/ +s/\*\([0-9*]*\)/*\1+\1/ +b mul + +# get rid of a plus term until 0+x -> x +: add +/^\+\([0-9+*]*\)=/{ + s//\1/ + b loop +} +/^\([0-9*]*\)\+=/{ + s//\1/ + b loop +} +/^\([0-9]*\)\+\([0-9*+]*\)\+=/{ + s//\2+\1/ + b loop +} +/^\([0-9]*\)0\+\([0-9]*\)\([0-9]\)=/{ + s//\1+\2=\3/ + b add +} +/^\([0-9]*\)\([0-9]\)\+\([0-9]*\)0=/{ + s//\1+\3=\2/ + b add +} +/^\([0-9]*\)0\+\([0-9*+]*\)\+\([0-9]*\)\([0-9]\)=/{ + s//\1+\2+\3=\4/ + b add +} +/^\([0-9]*\)\([0-9]\)\+\([0-9*+]*\)\+\([0-9]*\)0=/{ + s//\1+\3+\4=\2/ + b add +} +s/^\([0-9]*\)1\+/\10+/ +s/^\([0-9]*\)2\+/\11+/ +s/^\([0-9]*\)3\+/\12+/ +s/^\([0-9]*\)4\+/\13+/ +s/^\([0-9]*\)5\+/\14+/ +s/^\([0-9]*\)6\+/\15+/ +s/^\([0-9]*\)7\+/\16+/ +s/^\([0-9]*\)8\+/\17+/ +s/^\([0-9]*\)9\+/\18+/ + +s/9=\([0-9]*\)$/_=\1/ +s/8=\([0-9]*\)$/9=\1/ +s/7=\([0-9]*\)$/8=\1/ +s/6=\([0-9]*\)$/7=\1/ +s/5=\([0-9]*\)$/6=\1/ +s/4=\([0-9]*\)$/5=\1/ +s/3=\([0-9]*\)$/4=\1/ +s/2=\([0-9]*\)$/3=\1/ +s/1=\([0-9]*\)$/2=\1/ +/_/{ + s//_0/ + : inc + s/9_/_0/ + s/8_/9/ + s/7_/8/ + s/6_/7/ + s/5_/6/ + s/4_/5/ + s/3_/4/ + s/2_/3/ + s/1_/2/ + s/0_/1/ + s/\+_/+1/ + /_/b inc +} +b add diff --git a/usr.bin/sed/TEST/sed.test b/usr.bin/sed/TEST/sed.test new file mode 100644 index 0000000..e91036f --- /dev/null +++ b/usr.bin/sed/TEST/sed.test @@ -0,0 +1,552 @@ +#!/bin/sh - +# +# Copyright (c) 1992 Diomidis Spinellis. +# 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. +# +# @(#)sed.test 8.1 (Berkeley) 6/6/93 +# + +# sed Regression Tests +# +# The following files are created: +# lines[1-4], script1, script2 +# Two directories *.out contain the test results + +main() +{ + BASE=/usr/old/bin/sed + BASELOG=sed.out + TEST=../obj/sed + TESTLOG=nsed.out + DICT=/usr/share/dict/words + + test_error | more + + awk 'END { for (i = 1; i < 15; i++) print "l1_" i}' lines1 + awk 'END { for (i = 1; i < 10; i++) print "l2_" i}' lines2 + + exec 4>&1 5>&2 + + # Set these flags to get messages about known problems + BSD=1 + GNU=0 + SUN=0 + tests $BASE $BASELOG + + BSD=0 + GNU=0 + SUN=0 + tests $TEST $TESTLOG + exec 1>&4 2>&5 + diff -c $BASELOG $TESTLOG | more +} + +tests() +{ + SED=$1 + DIR=$2 + rm -rf $DIR + mkdir $DIR + MARK=100 + + test_args + test_addr + echo Testing commands + test_group + test_acid + test_branch + test_pattern + test_print + test_subst +} + +mark() +{ + MARK=`expr $MARK + 1` + exec 1>&4 2>&5 + exec >"$DIR/${MARK}_$1" + echo "Test $1:$MARK" + # Uncomment this line to match tests with sed error messages + echo "Test $1:$MARK" >&5 +} + +test_args() +{ + mark '1.1' + echo Testing argument parsing + echo First type + if [ $SUN -eq 1 ] ; then + echo SunOS sed prints only with -n + else + $SED 's/^/e1_/p' lines1 + fi + mark '1.2' ; $SED -n 's/^/e1_/p' lines1 + mark '1.3' + if [ $SUN -eq 1 ] ; then + echo SunOS sed prints only with -n + else + $SED 's/^/e1_/p' script1 + echo 's/^/s2_/p' >script2 + mark '1.5' + if [ $SUN -eq 1 ] ; then + echo SunOS sed prints only with -n + else + $SED -f script1 lines1 + fi + mark '1.6' + if [ $SUN -eq 1 ] ; then + echo SunOS sed prints only with -n + else + $SED -f script1 script1 <lines3 + # GNU and SunOS sed behave differently here + mark '7.1' + if [ $BSD -eq 1 ] ; then + echo 'BSD sed drops core on this one; TEST SKIPPED' + else + $SED -n l lines3 + fi + mark '7.2' ; $SED -e '/l2_/=' lines1 lines2 + rm -f lines4 + mark '7.3' ; $SED -e '3,12w lines4' lines1 + echo w results + cat lines4 + mark '7.4' ; $SED -e '4r lines2' lines1 + mark '7.5' ; $SED -e '5r /dev/dds' lines1 + mark '7.6' ; $SED -e '6r /dev/null' lines1 + mark '7.7' + if [ $BSD -eq 1 -o $GNU -eq 1 -o $SUN -eq 1 ] ; then + echo BSD, GNU and SunOS cannot pass this one + else + sed '200q' $DICT | sed 's$.*$s/^/&/w tmpdir/&$' >script1 + rm -rf tmpdir + mkdir tmpdir + $SED -f script1 lines1 + cat tmpdir/* + rm -rf tmpdir + fi + mark '7.8' + if [ $BSD -eq 1 ] ; then + echo BSD sed cannot pass 7.7 + else + echo line1 > lines3 + echo "" >> lines3 + $SED -n -e '$p' lines3 /dev/null + fi + +} + +test_subst() +{ + echo Testing substitution commands + mark '8.1' ; $SED -e 's/./X/g' lines1 + mark '8.2' ; $SED -e 's,.,X,g' lines1 +# GNU and SunOS sed thinks we are escaping . as wildcard, not as separator +# mark '8.3' ; $SED -e 's.\..X.g' lines1 +# POSIX does not say that this should work +# mark '8.4' ; $SED -e 's/[/]/Q/' lines1 + mark '8.4' ; $SED -e 's/[\/]/Q/' lines1 + mark '8.5' ; $SED -e 's_\__X_' lines1 + mark '8.6' ; $SED -e 's/./(&)/g' lines1 + mark '8.7' ; $SED -e 's/./(\&)/g' lines1 + mark '8.8' ; $SED -e 's/\(.\)\(.\)\(.\)/x\3x\2x\1/g' lines1 + mark '8.9' ; $SED -e 's/_/u0\ +u1\ +u2/g' lines1 + mark '8.10' + if [ $BSD -eq 1 -o $GNU -eq 1 ] ; then + echo 'BSD/GNU sed do not understand digit flags on s commands' + fi + $SED -e 's/./X/4' lines1 + rm -f lines4 + mark '8.11' ; $SED -e 's/1/X/w lines4' lines1 + echo s wfile results + cat lines4 + mark '8.12' ; $SED -e 's/[123]/X/g' lines1 + mark '8.13' ; $SED -e 'y/0123456789/9876543210/' lines1 + mark '8.14' ; + if [ $BSD -eq 1 -o $GNU -eq 1 -o $SUN -eq 1 ] ; then + echo BSD/GNU/SUN sed fail this test + else + $SED -e 'y10\123456789198765432\101' lines1 + fi + mark '8.15' ; $SED -e '1N;2y/\n/X/' lines1 + mark '8.16' + if [ $BSD -eq 1 ] ; then + echo 'BSD sed does not handle branch defined REs' + else + echo 'eeefff' | $SED -e 'p' -e 's/e/X/p' -e ':x' \ + -e 's//Y/p' -e '/f/bx' + fi +} + +test_error() +{ + exec 0>&3 4>&1 5>&2 + exec 0&1 + set -x + $TEST -x && exit 1 + $TEST -f && exit 1 + $TEST -e && exit 1 + $TEST -f /dev/dds && exit 1 + $TEST p /dev/dds && exit 1 + $TEST -f /bin/sh && exit 1 + $TEST '{' && exit 1 + $TEST '{' && exit 1 + $TEST '/hello/' && exit 1 + $TEST '1,/hello/' && exit 1 + $TEST -e '-5p' && exit 1 + $TEST '/jj' && exit 1 + $TEST 'a hello' && exit 1 + $TEST 'a \ hello' && exit 1 + $TEST 'b foo' && exit 1 + $TEST 'd hello' && exit 1 + $TEST 's/aa' && exit 1 + $TEST 's/aa/' && exit 1 + $TEST 's/a/b' && exit 1 + $TEST 's/a/b/c/d' && exit 1 + $TEST 's/a/b/ 1 2' && exit 1 + $TEST 's/a/b/ 1 g' && exit 1 + $TEST 's/a/b/w' && exit 1 + $TEST 'y/aa' && exit 1 + $TEST 'y/aa/b/' && exit 1 + $TEST 'y/aa/' && exit 1 + $TEST 'y/a/b' && exit 1 + $TEST 'y/a/b/c/d' && exit 1 + $TEST '!' && exit 1 + $TEST supercalifrangolisticexprialidociussupercalifrangolisticexcius + set +x + exec 0>&3 1>&4 2>&5 +} + +main diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c new file mode 100644 index 0000000..944a226 --- /dev/null +++ b/usr.bin/sed/compile.c @@ -0,0 +1,771 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_delimited __P((char *, char *)); +static char *compile_flags __P((char *, struct s_subst *)); +static char *compile_re __P((char *, regex_t **)); +static char *compile_subst __P((char *, struct s_subst *)); +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 *, char *)); +static void enterlabel __P((struct s_command *)); +static 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. + */ +struct s_format { + char code; /* Command code */ + int naddr; /* Number of address args */ + enum e_args args; /* Argument type */ +}; + +static struct s_format cmd_fmts[] = { + {'{', 2, GROUP}, + {'a', 1, TEXT}, + {'b', 2, BRANCH}, + {'c', 2, TEXT}, + {'d', 2, EMPTY}, + {'D', 2, EMPTY}, + {'g', 2, EMPTY}, + {'G', 2, EMPTY}, + {'h', 2, EMPTY}, + {'H', 2, EMPTY}, + {'i', 1, TEXT}, + {'l', 2, EMPTY}, + {'n', 2, EMPTY}, + {'N', 2, EMPTY}, + {'p', 2, EMPTY}, + {'P', 2, EMPTY}, + {'q', 1, EMPTY}, + {'r', 1, RFILE}, + {'s', 2, SUBST}, + {'t', 2, BRANCH}, + {'w', 2, WFILE}, + {'x', 2, EMPTY}, + {'y', 2, TR}, + {'!', 2, NONSEL}, + {':', 0, LABEL}, + {'#', 0, COMMENT}, + {'=', 1, EMPTY}, + {'\0', 0, COMMENT}, +}; + +/* The compiled program. */ +struct s_command *prog; + +/* + * Compile the program into prog. + * Initialise appends. + */ +void +compile() +{ + *compile_stream(NULL, &prog, NULL) = NULL; + fixuplabel(prog, NULL); + uselabel(); + appends = xmalloc(sizeof(struct s_appends) * appendnum); + match = xmalloc((maxnsub + 1) * sizeof(regmatch_t)); +} + +#define EATSPACE() do { \ + if (p) \ + while (*p && isascii(*p) && isspace(*p)) \ + p++; \ + } while (0) + +static struct s_command ** +compile_stream(terminator, link, p) + char *terminator; + struct s_command **link; + register char *p; +{ + static char lbuf[_POSIX2_LINE_MAX + 1]; /* To save stack */ + struct s_command *cmd, *cmd2; + struct s_format *fp; + int naddr; /* Number of addresses */ + + if (p != NULL) + goto semicolon; + for (;;) { + if ((p = cu_fgets(lbuf, sizeof(lbuf))) == NULL) { + if (terminator != NULL) + err(COMPILE, "unexpected EOF (pending }'s)"); + return (link); + } + +semicolon: EATSPACE(); + if (p && (*p == '#' || *p == '\0')) + continue; + if (*p == '}') { + if (terminator == NULL) + err(COMPILE, "unexpected }"); + return (link); + } + *link = cmd = xmalloc(sizeof(struct s_command)); + link = &cmd->next; + cmd->nonsel = cmd->inrange = 0; + /* First parse the addresses */ + naddr = 0; + cmd->a1 = cmd->a2 = NULL; + +/* Valid characters to start an address */ +#define addrchar(c) (strchr("0123456789/\\$", (c))) + if (addrchar(*p)) { + naddr++; + cmd->a1 = xmalloc(sizeof(struct s_addr)); + p = compile_addr(p, cmd->a1); + EATSPACE(); /* EXTENSION */ + if (*p == ',') { + naddr++; + p++; + EATSPACE(); /* EXTENSION */ + cmd->a2 = xmalloc(sizeof(struct s_addr)); + p = compile_addr(p, cmd->a2); + } + } + +nonsel: /* Now parse the command */ + EATSPACE(); + if (!*p) + err(COMPILE, "command expected"); + cmd->code = *p; + for (fp = cmd_fmts; fp->code; fp++) + if (fp->code == *p) + break; + if (!fp->code) + err(COMPILE, "invalid command code %c", *p); + if (naddr > fp->naddr) + err(COMPILE, +"command %c expects up to %d address(es), found %d", *p, fp->naddr, naddr); + switch (fp->args) { + case NONSEL: /* ! */ + cmd->nonsel = ! cmd->nonsel; + p++; + goto nonsel; + case GROUP: /* { */ + p++; + EATSPACE(); + if (!*p) + p = NULL; + cmd2 = xmalloc(sizeof(struct s_command)); + cmd2->code = '}'; + *compile_stream("}", &cmd->u.c, p) = cmd2; + cmd->next = cmd2; + link = &cmd2->next; + break; + case EMPTY: /* d D g G h H l n N p P q x = \0 */ + p++; + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + if (*p) + err(COMPILE, +"extra characters at the end of %c command", cmd->code); + break; + case TEXT: /* a c i */ + p++; + EATSPACE(); + if (*p != '\\') + err(COMPILE, +"command %c expects \\ followed by text", cmd->code); + p++; + EATSPACE(); + if (*p) + err(COMPILE, +"extra characters after \\ at the end of %c command", cmd->code); + cmd->t = compile_text(); + break; + case COMMENT: /* \0 # */ + break; + case WFILE: /* w */ + p++; + EATSPACE(); + if (*p == '\0') + err(COMPILE, "filename expected"); + cmd->t = duptoeol(p, "w command"); + if (aflag) + cmd->u.fd = -1; + else if ((cmd->u.fd = open(p, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + err(FATAL, "%s: %s\n", p, strerror(errno)); + break; + case RFILE: /* r */ + p++; + EATSPACE(); + if (*p == '\0') + err(COMPILE, "filename expected"); + else + cmd->t = duptoeol(p, "read command"); + break; + case BRANCH: /* b t */ + p++; + EATSPACE(); + if (*p == '\0') + cmd->t = NULL; + else + cmd->t = duptoeol(p, "branch"); + break; + case LABEL: /* : */ + p++; + EATSPACE(); + cmd->t = duptoeol(p, "label"); + if (strlen(p) == 0) + err(COMPILE, "empty label"); + enterlabel(cmd); + break; + case SUBST: /* s */ + p++; + if (*p == '\0' || *p == '\\') + err(COMPILE, +"substitute pattern can not be delimited by newline or backslash"); + cmd->u.s = xmalloc(sizeof(struct s_subst)); + p = compile_re(p, &cmd->u.s->re); + if (p == NULL) + err(COMPILE, "unterminated substitute pattern"); + --p; + p = compile_subst(p, cmd->u.s); + p = compile_flags(p, cmd->u.s); + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + break; + case TR: /* y */ + p++; + p = compile_tr(p, (char **)&cmd->u.y); + EATSPACE(); + if (*p == ';') { + p++; + link = &cmd->next; + goto semicolon; + } + if (*p) + err(COMPILE, +"extra text at the end of a transform command"); + break; + } + } +} + +/* + * Get a delimited string. P points to the delimeter of the string; d points + * to a buffer area. Newline and delimiter escapes are processed; other + * escapes are ignored. + * + * Returns a pointer to the first character after the final delimiter or NULL + * in the case of a non-terminated string. The character array d is filled + * with the processed string. + */ +static char * +compile_delimited(p, d) + char *p, *d; +{ + char c; + + c = *p++; + if (c == '\0') + return (NULL); + else if (c == '\\') + err(COMPILE, "\\ can not be used as a string delimiter"); + else if (c == '\n') + err(COMPILE, "newline can not be used as a string delimiter"); + while (*p) { + if (*p == '\\' && p[1] == c) + p++; + else if (*p == '\\' && p[1] == 'n') { + *d++ = '\n'; + p += 2; + continue; + } else if (*p == '\\' && p[1] == '\\') + *d++ = *p++; + else if (*p == c) { + *d = '\0'; + return (p + 1); + } + *d++ = *p++; + } + return (NULL); +} + +/* + * Get a regular expression. P points to the delimiter of the regular + * expression; repp points to the address of a regexp pointer. Newline + * and delimiter escapes are processed; other escapes are ignored. + * Returns a pointer to the first character after the final delimiter + * or NULL in the case of a non terminated regular expression. The regexp + * pointer is set to the compiled regular expression. + * Cflags are passed to regcomp. + */ +static char * +compile_re(p, repp) + char *p; + regex_t **repp; +{ + int eval; + char re[_POSIX2_LINE_MAX + 1]; + + p = compile_delimited(p, re); + if (p && strlen(re) == 0) { + *repp = NULL; + return (p); + } + *repp = xmalloc(sizeof(regex_t)); + if (p && (eval = regcomp(*repp, re, 0)) != 0) + err(COMPILE, "RE error: %s", strregerror(eval, *repp)); + if (maxnsub < (*repp)->re_nsub) + maxnsub = (*repp)->re_nsub; + return (p); +} + +/* + * Compile the substitution string of a regular expression and set res to + * point to a saved copy of it. Nsub is the number of parenthesized regular + * expressions. + */ +static char * +compile_subst(p, s) + char *p; + struct s_subst *s; +{ + static char lbuf[_POSIX2_LINE_MAX + 1]; + int asize, ref, size; + char c, *text, *op, *sp; + + c = *p++; /* Terminator character */ + if (c == '\0') + return (NULL); + + s->maxbref = 0; + s->linenum = linenum; + asize = 2 * _POSIX2_LINE_MAX + 1; + text = xmalloc(asize); + size = 0; + do { + op = sp = text + size; + for (; *p; p++) { + if (*p == '\\') { + p++; + if (strchr("123456789", *p) != NULL) { + *sp++ = '\\'; + ref = *p - '0'; + if (s->re != NULL && + ref > s->re->re_nsub) + err(COMPILE, +"\\%c not defined in the RE", *p); + if (s->maxbref < ref) + s->maxbref = ref; + } else if (*p == '&' || *p == '\\') + *sp++ = '\\'; + } else if (*p == c) { + p++; + *sp++ = '\0'; + size += sp - op; + s->new = xrealloc(text, size); + return (p); + } else if (*p == '\n') { + err(COMPILE, +"unescaped newline inside substitute pattern"); + /* NOTREACHED */ + } + *sp++ = *p; + } + size += sp - op; + if (asize - size < _POSIX2_LINE_MAX + 1) { + asize *= 2; + text = xmalloc(asize); + } + } while (cu_fgets(p = lbuf, sizeof(lbuf))); + err(COMPILE, "unterminated substitute in regular expression"); + /* NOTREACHED */ +} + +/* + * Compile the flags of the s command + */ +static char * +compile_flags(p, s) + char *p; + struct s_subst *s; +{ + int gn; /* True if we have seen g or n */ + char wfile[_POSIX2_LINE_MAX + 1], *q; + + s->n = 1; /* Default */ + s->p = 0; + s->wfile = NULL; + s->wfd = -1; + for (gn = 0;;) { + EATSPACE(); /* EXTENSION */ + switch (*p) { + case 'g': + if (gn) + err(COMPILE, +"more than one number or 'g' in substitute flags"); + gn = 1; + s->n = 0; + break; + case '\0': + case '\n': + case ';': + return (p); + case 'p': + s->p = 1; + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + if (gn) + err(COMPILE, +"more than one number or 'g' in substitute flags"); + gn = 1; + /* XXX Check for overflow */ + s->n = (int)strtol(p, &p, 10); + break; + case 'w': + p++; +#ifdef HISTORIC_PRACTICE + if (*p != ' ') { + err(WARNING, "space missing before w wfile"); + return (p); + } +#endif + EATSPACE(); + q = wfile; + while (*p) { + if (*p == '\n') + break; + *q++ = *p++; + } + *q = '\0'; + if (q == wfile) + err(COMPILE, "no wfile specified"); + s->wfile = strdup(wfile); + if (!aflag && (s->wfd = open(wfile, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + err(FATAL, "%s: %s\n", wfile, strerror(errno)); + return (p); + default: + err(COMPILE, + "bad flag in substitute command: '%c'", *p); + break; + } + p++; + } +} + +/* + * Compile a translation set of strings into a lookup table. + */ +static char * +compile_tr(p, transtab) + char *p; + char **transtab; +{ + int i; + char *lt, *op, *np; + char old[_POSIX2_LINE_MAX + 1]; + char new[_POSIX2_LINE_MAX + 1]; + + if (*p == '\0' || *p == '\\') + err(COMPILE, +"transform pattern can not be delimited by newline or backslash"); + p = compile_delimited(p, old); + if (p == NULL) { + err(COMPILE, "unterminated transform source string"); + return (NULL); + } + p = compile_delimited(--p, new); + if (p == NULL) { + err(COMPILE, "unterminated transform target string"); + return (NULL); + } + EATSPACE(); + if (strlen(new) != strlen(old)) { + err(COMPILE, "transform strings are not the same length"); + return (NULL); + } + /* We assume characters are 8 bits */ + lt = xmalloc(UCHAR_MAX); + for (i = 0; i <= UCHAR_MAX; i++) + lt[i] = (char)i; + for (op = old, np = new; *op; op++, np++) + lt[(u_char)*op] = *np; + *transtab = lt; + return (p); +} + +/* + * Compile the text following an a or i command. + */ +static char * +compile_text() +{ + int asize, size; + char *text, *p, *op, *s; + char lbuf[_POSIX2_LINE_MAX + 1]; + + asize = 2 * _POSIX2_LINE_MAX + 1; + text = xmalloc(asize); + size = 0; + while (cu_fgets(lbuf, sizeof(lbuf))) { + op = s = text + size; + p = lbuf; + EATSPACE(); + for (; *p; p++) { + if (*p == '\\') + p++; + *s++ = *p; + } + size += s - op; + if (p[-2] != '\\') { + *s = '\0'; + break; + } + if (asize - size < _POSIX2_LINE_MAX + 1) { + asize *= 2; + text = xmalloc(asize); + } + } + return (xrealloc(text, size + 1)); +} + +/* + * Get an address and return a pointer to the first character after + * it. Fill the structure pointed to according to the address. + */ +static char * +compile_addr(p, a) + char *p; + struct s_addr *a; +{ + char *end; + + switch (*p) { + case '\\': /* Context address */ + ++p; + /* FALLTHROUGH */ + case '/': /* Context address */ + p = compile_re(p, &a->u.r); + if (p == NULL) + err(COMPILE, "unterminated regular expression"); + a->type = AT_RE; + return (p); + + case '$': /* Last line */ + a->type = AT_LAST; + return (p + 1); + /* Line number */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + a->type = AT_LINE; + a->u.l = strtol(p, &end, 10); + return (end); + default: + err(COMPILE, "expected context address"); + return (NULL); + } +} + +/* + * duptoeol -- + * Return a copy of all the characters up to \n or \0. + */ +static char * +duptoeol(s, ctype) + register char *s; + char *ctype; +{ + size_t len; + int ws; + char *start; + + 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)); +} + +/* + * 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(cp, end) + struct s_command *cp, *end; +{ + + for (; cp != end; cp = cp->next) + switch (cp->code) { + case 'a': + case 'r': + appendnum++; + break; + case 'b': + case 't': + /* Resolve branch target. */ + if (cp->t == NULL) { + cp->u.c = NULL; + break; + } + if ((cp->u.c = findlabel(cp->t)) == NULL) + err(COMPILE2, "undefined label '%s'", cp->t); + free(cp->t); + break; + case '{': + /* 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 new file mode 100644 index 0000000..3cc580f --- /dev/null +++ b/usr.bin/sed/defs.h @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)defs.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Types of address specifications + */ +enum e_atype { + AT_RE, /* Line that match RE */ + AT_LINE, /* Specific line */ + AT_LAST, /* Last line */ +}; + +/* + * Format of an address + */ +struct s_addr { + enum e_atype type; /* Address type */ + union { + u_long l; /* Line number */ + regex_t *r; /* Regular expression */ + } u; +}; + +/* + * Substitution command + */ +struct s_subst { + int n; /* Occurrence to subst. */ + int p; /* True if p flag */ + char *wfile; /* NULL if no wfile */ + int wfd; /* Cached file descriptor */ + regex_t *re; /* Regular expression */ + int maxbref; /* Largest backreference. */ + u_long linenum; /* Line number. */ + char *new; /* Replacement text */ +}; + + +/* + * An internally compiled command. + * Initialy, label references are stored in t, on a second pass they + * are updated to pointers. + */ +struct s_command { + struct s_command *next; /* Pointer to next command */ + struct s_addr *a1, *a2; /* Start and end address */ + char *t; /* Text for : a c i r w */ + union { + struct s_command *c; /* Command(s) for b t { */ + struct s_subst *s; /* Substitute command */ + u_char *y; /* Replace command array */ + int fd; /* File descriptor for w */ + } u; + char code; /* Command code */ + u_int nonsel:1; /* True if ! */ + u_int inrange:1; /* True if in range */ +}; + +/* + * Types of command arguments recognised by the parser + */ +enum e_args { + EMPTY, /* d D g G h H l n N p P q x = \0 */ + TEXT, /* a c i */ + NONSEL, /* ! */ + GROUP, /* { */ + COMMENT, /* # */ + BRANCH, /* b t */ + LABEL, /* : */ + RFILE, /* r */ + WFILE, /* w */ + SUBST, /* s */ + TR /* y */ +}; + +/* + * Structure containing things to append before a line is read + */ +struct s_appends { + enum {AP_STRING, AP_FILE} type; + char *s; + size_t len; +}; + +enum e_spflag { + APPEND, /* Append to the contents. */ + REPLACE, /* Replace the contents. */ +}; + +/* + * Structure for a space (process, hold, otherwise). + */ +typedef struct { + char *space; /* Current space pointer. */ + size_t len; /* Current length. */ + int deleted; /* If deleted. */ + char *back; /* Backing memory. */ + size_t blen; /* Backing memory length. */ +} SPACE; + +/* + * Error severity codes: + */ +#define FATAL 0 /* Exit immediately with 1 */ +#define ERROR 1 /* Continue, but change exit value */ +#define WARNING 2 /* Just print the warning */ +#define COMPILE 3 /* Print error, count and finish script */ +#define COMPILE2 3 /* Print error, count and finish script */ diff --git a/usr.bin/sed/extern.h b/usr.bin/sed/extern.h new file mode 100644 index 0000000..54f2fb5 --- /dev/null +++ b/usr.bin/sed/extern.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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.h 8.1 (Berkeley) 6/6/93 + */ + +extern struct s_command *prog; +extern struct s_appends *appends; +extern regmatch_t *match; +extern size_t maxnsub; +extern u_long linenum; +extern int appendnum; +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)); +void process __P((void)); +char *strregerror __P((int, regex_t *)); +void *xmalloc __P((u_int)); +void *xrealloc __P((void *, u_int)); diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c new file mode 100644 index 0000000..14872fd --- /dev/null +++ b/usr.bin/sed/main.c @@ -0,0 +1,352 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "extern.h" + +/* + * Linked list of units (strings and files) to be compiled + */ +struct s_compunit { + struct s_compunit *next; + enum e_cut {CU_FILE, CU_STRING} type; + char *s; /* Pointer to string or fname */ +}; + +/* + * Linked list pointer to compilation units and pointer to current + * next pointer. + */ +static struct s_compunit *script, **cu_nextp = &script; + +/* + * Linked list of files to be processed + */ +struct s_flist { + char *fname; + struct s_flist *next; +}; + +/* + * Linked list pointer to files and pointer to current + * next pointer. + */ +static struct s_flist *files, **fl_nextp = &files; + +int aflag, eflag, nflag; + +/* + * Current file and line number; line numbers restart across compilation + * units, but span across input files. + */ +char *fname; /* File name. */ +u_long linenum; +int lastline; /* TRUE on the last line of the last file */ + +static void add_compunit __P((enum e_cut, char *)); +static void add_file __P((char *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c, fflag; + + fflag = 0; + while ((c = getopt(argc, argv, "ae:f:n")) != EOF) + switch (c) { + case 'a': + aflag = 1; + break; + case 'e': + eflag = 1; + add_compunit(CU_STRING, optarg); + break; + case 'f': + fflag = 1; + add_compunit(CU_FILE, optarg); + break; + case 'n': + nflag = 1; + break; + default: + case '?': + (void)fprintf(stderr, +"usage:\tsed script [-an] [file ...]\n\tsed [-an] [-e script] ... [-f scipt_file] ... [file ...]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + /* First usage case; script is the first arg */ + if (!eflag && !fflag && *argv) { + add_compunit(CU_STRING, *argv); + argv++; + } + + compile(); + + /* Continue with first and start second usage */ + if (*argv) + for (; *argv; argv++) + add_file(*argv); + else + add_file(NULL); + process(); + cfclose(prog, NULL); + if (fclose(stdout)) + err(FATAL, "stdout: %s", strerror(errno)); + exit (0); +} + +/* + * Like fgets, but go through the chain of compilation units chaining them + * together. Empty strings and files are ignored. + */ +char * +cu_fgets(buf, n) + char *buf; + int n; +{ + static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF; + static FILE *f; /* Current open file */ + static char *s; /* Current pointer inside string */ + static char string_ident[30]; + char *p; + +again: + switch (state) { + case ST_EOF: + if (script == NULL) + return (NULL); + linenum = 0; + switch (script->type) { + case CU_FILE: + if ((f = fopen(script->s, "r")) == NULL) + err(FATAL, + "%s: %s", script->s, strerror(errno)); + fname = script->s; + state = ST_FILE; + goto again; + case CU_STRING: + if ((snprintf(string_ident, + sizeof(string_ident), "\"%s\"", script->s)) >= + sizeof(string_ident) - 1) + (void)strcpy(string_ident + + sizeof(string_ident) - 6, " ...\""); + fname = string_ident; + s = script->s; + state = ST_STRING; + goto again; + } + case ST_FILE: + if ((p = fgets(buf, n, f)) != NULL) { + linenum++; + if (linenum == 1 && buf[0] == '#' && buf[1] == 'n') + nflag = 1; + return (p); + } + script = script->next; + (void)fclose(f); + state = ST_EOF; + goto again; + case ST_STRING: + if (linenum == 0 && s[0] == '#' && s[1] == 'n') + nflag = 1; + p = buf; + for (;;) { + if (n-- <= 1) { + *p = '\0'; + linenum++; + return (buf); + } + switch (*s) { + case '\0': + state = ST_EOF; + if (s == script->s) { + script = script->next; + goto again; + } else { + script = script->next; + *p = '\0'; + linenum++; + return (buf); + } + case '\n': + *p++ = '\n'; + *p = '\0'; + s++; + linenum++; + return (buf); + default: + *p++ = *s++; + } + } + } + /* NOTREACHED */ +} + +/* + * Like fgets, but go through the list of files chaining them together. + * Set len to the length of the line. + */ +int +mf_fgets(sp, spflag) + SPACE *sp; + enum e_spflag spflag; +{ + static FILE *f; /* Current open file */ + size_t len; + char c, *p; + + if (f == NULL) + /* Advance to first non-empty file */ + for (;;) { + if (files == NULL) { + lastline = 1; + return (0); + } + if (files->fname == NULL) { + f = stdin; + fname = "stdin"; + } else { + fname = files->fname; + if ((f = fopen(fname, "r")) == NULL) + err(FATAL, "%s: %s", + fname, strerror(errno)); + } + if ((c = getc(f)) != EOF) { + (void)ungetc(c, f); + break; + } + (void)fclose(f); + files = files->next; + } + + if (lastline) { + sp->len = 0; + return (0); + } + + /* + * 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 = fgetln(f, &len); + if (ferror(f)) + err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); + cspace(sp, p, len, spflag); + + linenum++; + /* Advance to next non-empty file */ + while ((c = getc(f)) == EOF) { + (void)fclose(f); + files = files->next; + if (files == NULL) { + lastline = 1; + return (1); + } + if (files->fname == NULL) { + f = stdin; + fname = "stdin"; + } else { + fname = files->fname; + if ((f = fopen(fname, "r")) == NULL) + err(FATAL, "%s: %s", fname, strerror(errno)); + } + } + (void)ungetc(c, f); + return (1); +} + +/* + * Add a compilation unit to the linked list + */ +static void +add_compunit(type, s) + enum e_cut type; + char *s; +{ + struct s_compunit *cu; + + cu = xmalloc(sizeof(struct s_compunit)); + cu->type = type; + cu->s = s; + cu->next = NULL; + *cu_nextp = cu; + cu_nextp = &cu->next; +} + +/* + * Add a file to the linked list + */ +static void +add_file(s) + char *s; +{ + struct s_flist *fp; + + fp = xmalloc(sizeof(struct s_flist)); + fp->next = NULL; + *fl_nextp = fp; + fp->fname = s; + fl_nextp = &fp->next; +} diff --git a/usr.bin/sed/misc.c b/usr.bin/sed/misc.c new file mode 100644 index 0000000..444b7a8 --- /dev/null +++ b/usr.bin/sed/misc.c @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include + +#include "defs.h" +#include "extern.h" + +/* + * malloc with result test + */ +void * +xmalloc(size) + u_int size; +{ + void *p; + + if ((p = malloc(size)) == NULL) + err(FATAL, "%s", strerror(errno)); + return (p); +} + +/* + * realloc with result test + */ +void * +xrealloc(p, size) + void *p; + u_int size; +{ + if (p == NULL) /* Compatibility hack. */ + return (xmalloc(size)); + + if ((p = realloc(p, size)) == NULL) + err(FATAL, "%s", strerror(errno)); + return (p); +} + +/* + * Return a string for a regular expression error passed. This is a overkill, + * because of the silly semantics of regerror (we can never know the size of + * the buffer). + */ +char * +strregerror(errcode, preg) + int errcode; + regex_t *preg; +{ + static char *oe; + size_t s; + + if (oe != NULL) + free(oe); + s = regerror(errcode, preg, "", 0); + oe = xmalloc(s); + (void)regerror(errcode, preg, oe, s); + return (oe); +} + +#if __STDC__ +#include +#else +#include +#endif +/* + * Error reporting function + */ +void +#if __STDC__ +err(int severity, const char *fmt, ...) +#else +err(severity, fmt, va_alist) + int severity; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "sed: "); + switch (severity) { + case WARNING: + case COMPILE: + (void)fprintf(stderr, "%lu: %s: ", linenum, fname); + } + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (severity == WARNING) + return; + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c new file mode 100644 index 0000000..2ec8aac --- /dev/null +++ b/usr.bin/sed/process.c @@ -0,0 +1,629 @@ +/*- + * Copyright (c) 1992 Diomidis Spinellis. + * 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 + * Diomidis Spinellis of Imperial College, University of London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)process.c 8.6 (Berkeley) 4/20/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "extern.h" + +static SPACE HS, PS, SS; +#define pd PS.deleted +#define ps PS.space +#define psl PS.len +#define hs HS.space +#define hsl HS.len + +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, size_t)); +static void regsub __P((SPACE *, char *, char *)); +static int substitute __P((struct s_command *)); + +struct s_appends *appends; /* Array of pointers to strings to append. */ +static int appendx; /* Index into appends array. */ +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 regex_t *defpreg; +size_t maxnsub; +regmatch_t *match; + +#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); } + +void +process() +{ + struct s_command *cp; + SPACE tspace; + size_t len; + char oldc, *p; + + for (linenum = 0; mf_fgets(&PS, REPLACE);) { + pd = 0; + cp = prog; +redirect: + while (cp != NULL) { + if (!applies(cp)) { + cp = cp->next; + continue; + } + switch (cp->code) { + case '{': + cp = cp->u.c; + goto redirect; + case 'a': + if (appendx >= appendnum) + appends = xrealloc(appends, + sizeof(struct s_appends) * + (appendnum *= 2)); + appends[appendx].type = AP_STRING; + appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); + appendx++; + break; + case 'b': + cp = cp->u.c; + goto redirect; + case 'c': + pd = 1; + psl = 0; + if (cp->a2 == NULL || lastaddr) + (void)printf("%s", cp->t); + break; + case 'd': + pd = 1; + goto new; + case 'D': + if (pd) + goto new; + if ((p = memchr(ps, '\n', psl)) == NULL) + pd = 1; + else { + psl -= (p - ps) + 1; + memmove(ps, p + 1, psl); + } + goto new; + case 'g': + cspace(&PS, hs, hsl, REPLACE); + break; + case 'G': + cspace(&PS, hs, hsl, 0); + break; + case 'h': + cspace(&HS, ps, psl, REPLACE); + break; + case 'H': + cspace(&HS, ps, psl, 0); + break; + case 'i': + (void)printf("%s", cp->t); + break; + case 'l': + lputs(ps); + break; + case 'n': + if (!nflag && !pd) + OUT(ps) + flush_appends(); + if (!mf_fgets(&PS, REPLACE)) + exit(0); + pd = 0; + break; + case 'N': + flush_appends(); + if (!mf_fgets(&PS, 0)) { + if (!nflag && !pd) + OUT(ps) + exit(0); + } + break; + case 'p': + if (pd) + break; + OUT(ps) + break; + case 'P': + if (pd) + break; + if ((p = memchr(ps, '\n', psl)) != NULL) { + oldc = *p; + *p = '\0'; + } + OUT(ps) + if (p != NULL) + *p = oldc; + break; + case 'q': + if (!nflag && !pd) + OUT(ps) + flush_appends(); + exit(0); + case 'r': + if (appendx >= appendnum) + appends = xrealloc(appends, + sizeof(struct s_appends) * + (appendnum *= 2)); + appends[appendx].type = AP_FILE; + appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); + appendx++; + break; + case 's': + sdone |= substitute(cp); + break; + case 't': + if (sdone) { + sdone = 0; + cp = cp->u.c; + goto redirect; + } + break; + case 'w': + if (pd) + break; + if (cp->u.fd == -1 && (cp->u.fd = open(cp->t, + O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, + DEFFILEMODE)) == -1) + err(FATAL, "%s: %s\n", + cp->t, strerror(errno)); + 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; + break; + case 'y': + if (pd) + break; + for (p = ps, len = psl; --len; ++p) + *p = cp->u.y[*p]; + break; + case ':': + case '}': + break; + case '=': + (void)printf("%lu\n", linenum); + } + cp = cp->next; + } /* for all cp */ + +new: if (!nflag && !pd) + OUT(ps) + flush_appends(); + } /* for all lines */ +} + +/* + * 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, psl) : \ + (a)->type == AT_LINE ? linenum == (a)->u.l : lastline + +/* + * Return TRUE if the command applies to the current line. Sets the inrange + * flag to process ranges. Interprets the non-select (``!'') flag. + */ +static inline int +applies(cp) + struct s_command *cp; +{ + int r; + + lastaddr = 0; + if (cp->a1 == NULL && cp->a2 == NULL) + r = 1; + else if (cp->a2) + if (cp->inrange) { + if (MATCH(cp->a2)) { + cp->inrange = 0; + lastaddr = 1; + } + r = 1; + } else if (MATCH(cp->a1)) { + /* + * If the second address is a number less than or + * equal to the line number first selected, only + * one line shall be selected. + * -- POSIX 1003.2 + */ + if (cp->a2->type == AT_LINE && + linenum >= cp->a2->u.l) + lastaddr = 1; + else + cp->inrange = 1; + r = 1; + } else + r = 0; + else + r = MATCH(cp->a1); + return (cp->nonsel ? ! r : r); +} + +/* + * substitute -- + * Do substitutions in the pattern space. Currently, we build a + * copy of the new pattern space in the substitute space structure + * and then swap them. + */ +static int +substitute(cp) + struct s_command *cp; +{ + SPACE tspace; + regex_t *re; + size_t re_off, slen; + int lastempty, n; + char *s; + + s = ps; + re = cp->u.s->re; + if (re == NULL) { + if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { + linenum = cp->u.s->linenum; + err(COMPILE, "\\%d not defined in the RE", + cp->u.s->maxbref); + } + } + 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 { + 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. */ + 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. */ + if (slen > 0) + cspace(&SS, s, slen, APPEND); + break; + default: /* Nth occurrence */ + while (--n) { + s += match[0].rm_eo; + slen -= match[0].rm_eo; + if (!regexec_e(re, s, REG_NOTBOL, 0, slen)) + return (0); + } + /* FALLTHROUGH */ + case 1: /* 1st occurrence */ + /* Locate start of replaced string. */ + re_off = match[0].rm_so + (s - ps); + /* Copy leading retained string. */ + cspace(&SS, ps, re_off, APPEND); + /* Add in regular expression. */ + regsub(&SS, s, cp->u.s->new); + /* Copy trailing retained string. */ + s += match[0].rm_eo; + slen -= match[0].rm_eo; + cspace(&SS, s, slen, APPEND); + break; + } + + /* + * Swap the substitute space and the pattern space, and make sure + * that any leftover pointers into stdio memory get lost. + */ + tspace = PS; + PS = SS; + SS = tspace; + SS.space = SS.back; + + /* Handle the 'p' flag. */ + if (cp->u.s->p) + 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)); + if (write(cp->u.s->wfd, ps, psl) != psl) + err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); + } + return (1); +} + +/* + * Flush append requests. Always called before reading a line, + * therefore it also resets the substitution done (sdone) flag. + */ +static void +flush_appends() +{ + FILE *f; + int count, i; + char buf[8 * 1024]; + + for (i = 0; i < appendx; i++) + switch (appends[i].type) { + case AP_STRING: + fwrite(appends[i].s, sizeof(char), appends[i].len, + stdout); + break; + case AP_FILE: + /* + * Read files probably shouldn't be cached. Since + * it's not an error to read a non-existent file, + * it's possible that another program is interacting + * with the sed script through the file system. It + * would be truly bizarre, but possible. It's probably + * not that big a performance win, anyhow. + */ + if ((f = fopen(appends[i].s, "r")) == NULL) + break; + while (count = fread(buf, sizeof(char), sizeof(buf), f)) + (void)fwrite(buf, sizeof(char), count, stdout); + (void)fclose(f); + break; + } + if (ferror(stdout)) + err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); + appendx = sdone = 0; +} + +static void +lputs(s) + register char *s; +{ + register int count; + register char *escapes, *p; + struct winsize win; + static int termwidth = -1; + + if (termwidth == -1) + if (p = getenv("COLUMNS")) + termwidth = atoi(p); + else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && + win.ws_col > 0) + termwidth = win.ws_col; + else + termwidth = 60; + + for (count = 0; *s; ++s) { + if (count >= termwidth) { + (void)printf("\\\n"); + count = 0; + } + if (isascii(*s) && isprint(*s) && *s != '\\') { + (void)putchar(*s); + count++; + } else { + escapes = "\\\a\b\f\n\r\t\v"; + (void)putchar('\\'); + if (p = strchr(escapes, *s)) { + (void)putchar("\\abfnrtv"[p - escapes]); + count += 2; + } else { + (void)printf("%03o", *(u_char *)s); + count += 4; + } + } + } + (void)putchar('$'); + (void)putchar('\n'); + if (ferror(stdout)) + err(FATAL, "stdout: %s", strerror(errno ? errno : EIO)); +} + +static inline int +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 | REG_STARTEND); + switch(eval) { + case 0: + return (1); + case REG_NOMATCH: + return (0); + } + err(FATAL, "RE error: %s", strregerror(eval, defpreg)); + /* NOTREACHED */ +} + +/* + * regsub - perform substitutions after a regexp match + * Based on a routine by Henry Spencer + */ +static void +regsub(sp, string, src) + SPACE *sp; + char *string, *src; +{ + register int len, no; + register char c, *dst; + +#define NEEDSP(reqlen) \ + if (sp->len >= sp->blen - (reqlen) - 1) { \ + sp->blen += (reqlen) + 1024; \ + sp->space = sp->back = xrealloc(sp->back, sp->blen); \ + dst = sp->space + sp->len; \ + } + + dst = sp->space + sp->len; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && isdigit(*src)) + no = *src++ - '0'; + else + no = -1; + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + NEEDSP(1); + *dst++ = c; + ++sp->len; + } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) { + len = match[no].rm_eo - match[no].rm_so; + NEEDSP(len); + memmove(dst, string + match[no].rm_so, len); + dst += len; + sp->len += len; + } + } + NEEDSP(1); + *dst = '\0'; +} + +/* + * aspace -- + * Append the source space to the destination space, allocating new + * space as necessary. + */ +void +cspace(sp, p, len, spflag) + SPACE *sp; + char *p; + size_t len; + enum e_spflag spflag; +{ + size_t tlen; + + /* 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 == REPLACE) + sp->len = 0; + + memmove(sp->space + sp->len, p, len); + + sp->space[sp->len += len] = '\0'; +} + +/* + * Close all cached opened files and report any errors + */ +void +cfclose(cp, end) + register struct s_command *cp, *end; +{ + + for (; cp != end; cp = cp->next) + switch(cp->code) { + case 's': + if (cp->u.s->wfd != -1 && close(cp->u.s->wfd)) + err(FATAL, + "%s: %s", cp->u.s->wfile, strerror(errno)); + cp->u.s->wfd = -1; + break; + case 'w': + if (cp->u.fd != -1 && close(cp->u.fd)) + err(FATAL, "%s: %s", cp->t, strerror(errno)); + cp->u.fd = -1; + break; + case '{': + cfclose(cp->u.c, cp->next); + break; + } +} diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1 new file mode 100644 index 0000000..63bcd32 --- /dev/null +++ b/usr.bin/sed/sed.1 @@ -0,0 +1,514 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)sed.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd "December 30, 1993" +.Dt SED 1 +.Os +.Sh NAME +.Nm sed +.Nd stream editor +.Sh SYNOPSIS +.Nm sed +.Op Fl an +.Ar command +.Op Ar file ... +.Nm sed +.Op Fl an +.Op Fl e Ar command +.Op Fl f Ar command_file +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm sed +utility reads the specified files, or the standard input if no files +are specified, modifying the input as specified by a list of commands. +The input is then written to the standard output. +.Pp +A single command may be specified as the first argument to +.Nm sed . +Multiple commands may be specified by using the +.Fl e +or +.Fl f +options. +All commands are applied to the input in the order they are specified +regardless of their origin. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl a +The files listed as parameters for the +.Dq w +functions are created (or truncated) before any processing begins, +by default. +The +.Fl a +option causes +.Nm sed +to delay opening each file until a command containing the related +.Dq w +function is applied to a line of input. +.It Fl e Ar command +Append the editing commands specified by the +.Ar command +argument +to the list of commands. +.It Fl f Ar command_file +Append the editing commands found in the file +.Ar command_file +to the list of commands. +The editing commands should each be listed on a separate line. +.It Fl n +By default, each line of input is echoed to the standard output after +all of the commands have been applied to it. +The +.Fl n +option suppresses this behavior. +.El +.Pp +The form of a +.Nm sed +command is as follows: +.sp +.Dl [address[,address]]function[arguments] +.sp +Whitespace may be inserted before the first address and the function +portions of the command. +.Pp +Normally, +.Nm sed +cyclically copies a line of input, not including its terminating newline +character, into a +.Em "pattern space" , +(unless there is something left after a +.Dq D +function), +applies all of the commands with addresses that select that pattern space, +copies the pattern space to the standard output, appending a newline, and +deletes the pattern space. +.Pp +Some of the functions use a +.Em "hold space" +to save all or part of the pattern space for subsequent retrieval. +.Sh "Sed Addresses" +An address is not required, but if specified must be a number (that counts +input lines +cumulatively across input files), a dollar +.Po +.Dq $ +.Pc +character that addresses the last line of input, or a context address +(which consists of a regular expression preceded and followed by a +delimiter). +.Pp +A command line with no addresses selects every pattern space. +.Pp +A command line with one address selects all of the pattern spaces +that match the address. +.Pp +A command line with two addresses selects the inclusive range from +the first pattern space that matches the first address through the next +pattern space that matches the second. +(If the second address is a number less than or equal to the line number +first selected, only that line is selected.) +Starting at the first line following the selected range, +.Nm sed +starts looking again for the first address. +.Pp +Editing commands can be applied to non-selected pattern spaces by use +of the exclamation character +.Po +.Dq ! +.Pc +function. +.Sh "Sed Regular Expressions" +The +.Nm sed +regular expressions are basic regular expressions (BRE's, see +.Xr regex 3 +for more information). +In addition, +.Nm sed +has the following two additions to BRE's: +.sp +.Bl -enum -compact +.It +In a context address, any character other than a backslash +.Po +.Dq \e +.Pc +or newline character may be used to delimit the regular expression. +Also, putting a backslash character before the delimiting character +causes the character to be treated literally. +For example, in the context address \exabc\exdefx, the RE delimiter +is an +.Dq x +and the second +.Dq x +stands for itself, so that the regular expression is +.Dq abcxdef . +.sp +.It +The escape sequence \en matches a newline character embedded in the +pattern space. +You can't, however, use a literal newline character in an address or +in the substitute command. +.El +.Pp +One special feature of +.Nm sed +regular expressions is that they can default to the last regular +expression used. +If a regular expression is empty, i.e. just the delimiter characters +are specified, the last regular expression encountered is used instead. +The last regular expression is defined as the last regular expression +used as part of an address or substitute command, and at run-time, not +compile-time. +For example, the command +.Dq /abc/s//XXX/ +will substitute +.Dq XXX +for the pattern +.Dq abc . +.Sh "Sed Functions" +In the following list of commands, the maximum number of permissible +addresses for each command is indicated by [0addr], [1addr], or [2addr], +representing zero, one, or two addresses. +.Pp +The argument +.Em text +consists of one or more lines. +To embed a newline in the text, precede it with a backslash. +Other backslashes in text are deleted and the following character +taken literally. +.Pp +The +.Dq r +and +.Dq w +functions take an optional file parameter, which should be separated +from the function letter by white space. +Each file given as an argument to +.Nm sed +is created (or its contents truncated) before any input processing begins. +.Pp +The +.Dq b , +.Dq r , +.Dq s , +.Dq t , +.Dq w , +.Dq y , +.Dq ! , +and +.Dq \&: +functions all accept additional arguments. +The following synopses indicate which arguments have to be separated from +the function letters by white space characters. +.Pp +Two of the functions take a function-list. +This is a list of +.Nm sed +functions separated by newlines, as follows: +.Bd -literal -offset indent +{ function + function + ... + function +} +.Ed +.Pp +The +.Dq { +can be preceded by white space and can be followed by white space. +The function can be preceded by white space. +The terminating +.Dq } +must be preceded by a newline or optional white space. +.sp +.Bl -tag -width "XXXXXX" -compact +.It [2addr] function-list +Execute function-list only when the pattern space is selected. +.sp +.It [1addr]a\e +.It text +.br +Write +.Em text +to standard output immediately before each attempt to read a line of input, +whether by executing the +.Dq N +function or by beginning a new cycle. +.sp +.It [2addr]b[lable] +Branch to the +.Dq \&: +function with the specified label. +If the label is not specified, branch to the end of the script. +.sp +.It [2addr]c\e +.It text +.br +Delete the pattern space. +With 0 or 1 address or at the end of a 2-address range, +.Em text +is written to the standard output. +.sp +.It [2addr]d +Delete the pattern space and start the next cycle. +.sp +.It [2addr]D +Delete the initial segment of the pattern space through the first +newline character and start the next cycle. +.sp +.It [2addr]g +Replace the contents of the pattern space with the contents of the +hold space. +.sp +.It [2addr]G +Append a newline character followed by the contents of the hold space +to the pattern space. +.sp +.It [2addr]h +Replace the contents of the hold space with the contents of the +pattern space. +.sp +.It [2addr]H +Append a newline character followed by the contents of the pattern space +to the hold space. +.sp +.It [1addr]i\e +.It text +.br +Write +.Em text +to the standard output. +.sp +.It [2addr]l +(The letter ell.) +Write the pattern space to the standard output in a visually unambiguous +form. +This form is as follows: +.sp +.Bl -tag -width "carriage-returnXX" -offset indent -compact +.It backslash +\e +.It alert +\ea +.It form-feed +\ef +.It newline +\en +.It carriage-return +\er +.It tab +\et +.It vertical tab +\ev +.El +.Pp +Nonprintable characters are written as three-digit octal numbers (with a +preceding backslash) for each byte in the character (most significant byte +first). +Long lines are folded, with the point of folding indicated by displaying +a backslash followed by a newline. +The end of each line is marked with a +.Dq $ . +.sp +.It [2addr]n +Write the pattern space to the standard output if the default output has +not been suppressed, and replace the pattern space with the next line of +input. +.sp +.It [2addr]N +Append the next line of input to the pattern space, using an embedded +newline character to separate the appended material from the original +contents. +Note that the current line number changes. +.sp +.It [2addr]p +Write the pattern space to standard output. +.sp +.It [2addr]P +Write the pattern space, up to the first newline character to the +standard output. +.sp +.It [1addr]q +Branch to the end of the script and quit without starting a new cycle. +.sp +.It [1addr]r file +Copy the contents of +.Em file +to the standard output immediately before the next attempt to read a +line of input. +If +.Em file +cannot be read for any reason, it is silently ignored and no error +condition is set. +.sp +.It [2addr]s/regular expression/replacement/flags +Substitute the replacement string for the first instance of the regular +expression in the pattern space. +Any character other than backslash or newline can be used instead of +a slash to delimit the RE and the replacement. +Within the RE and the replacement, the RE delimiter itself can be used as +a literal character if it is preceded by a backslash. +.Pp +An ampersand +.Po +.Dq & +.Pc +appearing in the replacement is replaced by the string matching the RE. +The special meaning of +.Dq & +in this context can be suppressed by preceding it by a backslash. +The string +.Dq \e# , +where +.Dq # +is a digit, is replaced by the text matched +by the corresponding backreference expression (see +.Xr re_format 7 ). +.Pp +A line can be split by substituting a newline character into it. +To specify a newline character in the replacement string, precede it with +a backslash. +.Pp +The value of +.Em flags +in the substitute function is zero or more of the following: +.Bl -tag -width "XXXXXX" -offset indent +.It "0 ... 9" +Make the substitution only for the N'th occurrence of the regular +expression in the pattern space. +.It g +Make the substitution for all non-overlapping matches of the +regular expression, not just the first one. +.It p +Write the pattern space to standard output if a replacement was made. +If the replacement string is identical to that which it replaces, it +is still considered to have been a replacement. +.It w Em file +Append the pattern space to +.Em file +if a replacement was made. +If the replacement string is identical to that which it replaces, it +is still considered to have been a replacement. +.El +.sp +.It [2addr]t [label] +Branch to the +.Dq : +function bearing the label if any substitutions have been made since the +most recent reading of an input line or execution of a +.Dq t +function. +If no label is specified, branch to the end of the script. +.sp +.It [2addr]w Em file +Append the pattern space to the +.Em file . +.sp +.It [2addr]x +Swap the contents of the pattern and hold spaces. +.sp +.It [2addr]y/string1/string2/ +Replace all occurrences of characters in +.Em string1 +in the pattern space with the corresponding characters from +.Em string2 . +Any character other than a backslash or newline can be used instead of +a slash to delimit the strings. +Within +.Em string1 +and +.Em string2 , +a backslash followed by any character other than a newline is that literal +character, and a backslash followed by an ``n'' is replaced by a newline +character. +.sp +.It [2addr]!function +.It [2addr]!function-list +Apply the function or function-list only to the lines that are +.Em not +selected by the address(es). +.sp +.It [0addr]:label +This function does nothing; it bears a label to which the +.Dq b +and +.Dq t +commands may branch. +.sp +.It [1addr]= +Write the line number to the standard output followed by a newline +character. +.sp +.It [0addr] +Empty lines are ignored. +.sp +.It [0addr]# +The +.Dq # +and the remainder of the line are ignored (treated as a comment), with +the single exception that if the first two characters in the file are +.Dq #n , +the default output is suppressed. +This is the same as specifying the +.Fl n +option on the command line. +.El +.Pp +The +.Nm sed +utility exits 0 on success and >0 if an error occurs. +.Sh SEE ALSO +.Xr awk 1 , +.Xr ed 1 , +.Xr grep 1 , +.Xr regex 3 , +.Xr re_format 7 +.Sh HISTORY +A +.Nm sed +command appeared in +.At v7 . +.Sh STANDARDS +The +.Nm sed +function is expected to be a superset of the +.St -p1003.2 +specification. diff --git a/usr.bin/shar/Makefile b/usr.bin/shar/Makefile new file mode 100644 index 0000000..2d8a5de --- /dev/null +++ b/usr.bin/shar/Makefile @@ -0,0 +1,16 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +MAN1= shar.0 + +all shar: ${MAN1} + +clean depend lint tags: + +cleandir: + rm -f ${MAN1} + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/shar.sh ${DESTDIR}/usr/bin/shar + +.include diff --git a/usr.bin/shar/shar.1 b/usr.bin/shar/shar.1 new file mode 100644 index 0000000..71202ee --- /dev/null +++ b/usr.bin/shar/shar.1 @@ -0,0 +1,102 @@ +.\" 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)shar.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt SHAR 1 +.Os BSD 4.4 +.Sh NAME +.Nm shar +.Nd create a shell archive of files +.Sh SYNOPSIS +.Nm shar Ar +.Sh DESCRIPTION +.Nm Shar +writes an +.Xr sh 1 +shell script to the standard output which will recreate the file +hierarchy specified by the command line operands. +Directories will be recreated and must be specified before the +files they contain (the +.Xr find 1 +utility does this correctly). +.Pp +.Nm Shar +is normally used for distributing files by +.Xr ftp 1 +or +.Xr mail 1 . +.Sh SEE ALSO +.Xr compress 1 , +.Xr mail 1 , +.Xr uuencode 1 , +.Xr tar 1 +.Sh BUGS +.Nm Shar +makes no provisions for special types of files or files containing +magic characters. +.Pp +It is easy to insert trojan horses into +.Nm shar +files. +It is strongly recommended that all shell archive files be examined +before running them through +.Xr sh 1 . +Archives produced using this implementation of +.Nm shar +may be easily examined with the command: +.Bd -literal -offset indent +egrep -v '^[X#]' shar.file +.Ed +.Sh EXAMPLES +To create a shell archive of the program +.Xr ls 1 +and mail it to Rick: +.Bd -literal -offset indent +cd ls +shar `find . -print` \&| mail -s "ls source" rick +.Ed +.Pp +To recreate the program directory: +.Bd -literal -offset indent +mkdir ls +cd ls +... + +... +sh archive +.Ed +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/shar/shar.sh b/usr.bin/shar/shar.sh new file mode 100644 index 0000000..08db22c --- /dev/null +++ b/usr.bin/shar/shar.sh @@ -0,0 +1,74 @@ +#!/bin/sh - +# +# 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 the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)shar.sh 8.1 (Berkeley) 6/6/93 +# + +if [ $# -eq 0 ]; then + echo 'usage: shar file ...' + exit 1 +fi + +cat << EOF +# This is a shell archive. Save it in a file, remove anything before +# this line, and then unpack it by entering "sh file". Note, it may +# create directories; files and directories will be owned by you and +# have default permissions. +# +# This archive contains: +# +EOF + +for i +do + echo "# $i" +done + +echo "#" + +for i +do + if [ -d $i ]; then + echo "echo c - $i" + echo "mkdir -p $i > /dev/null 2>&1" + else + echo "echo x - $i" + echo "sed 's/^X//' >$i << 'END-of-$i'" + sed 's/^/X/' $i + echo "END-of-$i" + fi +done +echo exit +echo "" + +exit 0 diff --git a/usr.bin/showmount/Makefile b/usr.bin/showmount/Makefile new file mode 100644 index 0000000..aa0074e --- /dev/null +++ b/usr.bin/showmount/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= showmount +DPADD= ${LIBRPC} +LDADD= -lrpc + +.include diff --git a/usr.bin/showmount/showmount.8 b/usr.bin/showmount/showmount.8 new file mode 100644 index 0000000..fe84e1e --- /dev/null +++ b/usr.bin/showmount/showmount.8 @@ -0,0 +1,88 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Rick Macklem at The University of Guelph. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)showmount.8 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt SHOWMOUNT 8 +.Os BSD 4 +.Sh NAME +.Nm showmount +.Nd show remote nfs mounts on host +.Sh SYNOPSIS +.Nm showmount +.Op Fl ade +.Op Ar host +.Sh DESCRIPTION +.Nm Showmount +shows status information about the +.Tn NFS +server on +.Ar host . +By default it prints the names of all hosts that have +.Tn NFS +file systems mounted +on the host. See +.%T "NFS: Network File System Protocol Specification" , +RFC 1094, +Appendix A , +for a detailed description of the protocol. +.Bl -tag -width Ds +.It Fl a +List all mount points in the form: +.Bd -ragged -offset indent -compact +.Ar host : Ns Ar dirpath +.Ed +.It Fl d +List directory paths of mount points instead of hosts +.It Fl e +Show the +.Ar host Ns 's +exports list +.El +.Sh SEE ALSO +.Xr mount 1 , +.Xr mountd 8 +.Sh BUGS +The mount daemon running on the server only has an idea of the actual mounts, +since the +.Tn NFS +server is stateless. +.Nm Showmount +will only display the information +as accurately as the mount daemon reports it. +.Sh HISTORY +The +.Nm showmount +utility first appeared in 4.4BSD. diff --git a/usr.bin/showmount/showmount.c b/usr.bin/showmount/showmount.c new file mode 100644 index 0000000..e5a3752 --- /dev/null +++ b/usr.bin/showmount/showmount.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)showmount.c 8.1 (Berkeley) 6/6/93"; +#endif not lint + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Constant defs */ +#define ALL 1 +#define DIRS 2 + +#define DODUMP 0x1 +#define DOEXPORTS 0x2 + +struct mountlist { + struct mountlist *ml_left; + struct mountlist *ml_right; + char ml_host[RPCMNT_NAMELEN+1]; + char ml_dirp[RPCMNT_PATHLEN+1]; +}; + +struct grouplist { + struct grouplist *gr_next; + char gr_name[RPCMNT_NAMELEN+1]; +}; + +struct exportslist { + struct exportslist *ex_next; + struct grouplist *ex_groups; + char ex_dirp[RPCMNT_PATHLEN+1]; +}; + +static struct mountlist *mntdump; +static struct exportslist *exports; +static int type = 0; +int xdr_mntdump(), xdr_exports(); + +/* + * This command queries the NFS mount daemon for it's mount list and/or + * it's exports list and prints them out. + * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" + * for detailed information on the protocol. + */ +main(argc, argv) + int argc; + char **argv; +{ + register struct mountlist *mntp; + register struct exportslist *exp; + register struct grouplist *grp; + extern char *optarg; + extern int optind; + register int rpcs = 0; + char ch; + char *host; + int estat; + + while ((ch = getopt(argc, argv, "ade")) != EOF) + switch((char)ch) { + case 'a': + if (type == 0) { + type = ALL; + rpcs |= DODUMP; + } else + usage(); + break; + case 'd': + if (type == 0) { + type = DIRS; + rpcs |= DODUMP; + } else + usage(); + break; + case 'e': + rpcs |= DOEXPORTS; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc > 0) + host = *argv; + else + host = "localhost"; + + if (rpcs == 0) + rpcs = DODUMP; + + if (rpcs & DODUMP) + if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1, + RPCMNT_DUMP, xdr_void, (char *)0, + xdr_mntdump, (char *)&mntdump)) != 0) { + clnt_perrno(estat); + fprintf(stderr, "Can't do Mountdump rpc\n"); + exit(1); + } + if (rpcs & DOEXPORTS) + if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1, + RPCMNT_EXPORT, xdr_void, (char *)0, + xdr_exports, (char *)&exports)) != 0) { + clnt_perrno(estat); + fprintf(stderr, "Can't do Exports rpc\n"); + exit(1); + } + + /* Now just print out the results */ + if (rpcs & DODUMP) { + switch (type) { + case ALL: + printf("All mount points on %s:\n", host); + break; + case DIRS: + printf("Directories on %s:\n", host); + break; + default: + printf("Hosts on %s:\n", host); + break; + }; + print_dump(mntdump); + } + if (rpcs & DOEXPORTS) { + printf("Exports list on %s:\n", host); + exp = exports; + while (exp) { + printf("%-35s", exp->ex_dirp); + grp = exp->ex_groups; + if (grp == NULL) { + printf("Everyone\n"); + } else { + while (grp) { + printf("%s ", grp->gr_name); + grp = grp->gr_next; + } + printf("\n"); + } + exp = exp->ex_next; + } + } +} + +/* + * Xdr routine for retrieving the mount dump list + */ +xdr_mntdump(xdrsp, mlp) + XDR *xdrsp; + struct mountlist **mlp; +{ + register struct mountlist *mp; + register struct mountlist *tp; + register struct mountlist **otp; + int val, val2; + int bool; + char *strp; + + *mlp = (struct mountlist *)0; + if (!xdr_bool(xdrsp, &bool)) + return (0); + while (bool) { + mp = (struct mountlist *)malloc(sizeof(struct mountlist)); + if (mp == NULL) + return (0); + mp->ml_left = mp->ml_right = (struct mountlist *)0; + strp = mp->ml_host; + if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) + return (0); + strp = mp->ml_dirp; + if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) + return (0); + + /* + * Build a binary tree on sorted order of either host or dirp. + * Drop any duplications. + */ + if (*mlp == NULL) { + *mlp = mp; + } else { + tp = *mlp; + while (tp) { + val = strcmp(mp->ml_host, tp->ml_host); + val2 = strcmp(mp->ml_dirp, tp->ml_dirp); + switch (type) { + case ALL: + if (val == 0) { + if (val2 == 0) { + free((caddr_t)mp); + goto next; + } + val = val2; + } + break; + case DIRS: + if (val2 == 0) { + free((caddr_t)mp); + goto next; + } + val = val2; + break; + default: + if (val == 0) { + free((caddr_t)mp); + goto next; + } + break; + }; + if (val < 0) { + otp = &tp->ml_left; + tp = tp->ml_left; + } else { + otp = &tp->ml_right; + tp = tp->ml_right; + } + } + *otp = mp; + } +next: + if (!xdr_bool(xdrsp, &bool)) + return (0); + } + return (1); +} + +/* + * Xdr routine to retrieve exports list + */ +xdr_exports(xdrsp, exp) + XDR *xdrsp; + struct exportslist **exp; +{ + register struct exportslist *ep; + register struct grouplist *gp; + int bool, grpbool; + char *strp; + + *exp = (struct exportslist *)0; + if (!xdr_bool(xdrsp, &bool)) + return (0); + while (bool) { + ep = (struct exportslist *)malloc(sizeof(struct exportslist)); + if (ep == NULL) + return (0); + ep->ex_groups = (struct grouplist *)0; + strp = ep->ex_dirp; + if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) + return (0); + if (!xdr_bool(xdrsp, &grpbool)) + return (0); + while (grpbool) { + gp = (struct grouplist *)malloc(sizeof(struct grouplist)); + if (gp == NULL) + return (0); + strp = gp->gr_name; + if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) + return (0); + gp->gr_next = ep->ex_groups; + ep->ex_groups = gp; + if (!xdr_bool(xdrsp, &grpbool)) + return (0); + } + ep->ex_next = *exp; + *exp = ep; + if (!xdr_bool(xdrsp, &bool)) + return (0); + } + return (1); +} + +usage() +{ + fprintf(stderr, "usage: showmount [-ade] host\n"); + exit(1); +} + +/* + * Print the binary tree in inorder so that output is sorted. + */ +print_dump(mp) + struct mountlist *mp; +{ + + if (mp == NULL) + return; + if (mp->ml_left) + print_dump(mp->ml_left); + switch (type) { + case ALL: + printf("%s:%s\n", mp->ml_host, mp->ml_dirp); + break; + case DIRS: + printf("%s\n", mp->ml_dirp); + break; + default: + printf("%s\n", mp->ml_host); + break; + }; + if (mp->ml_right) + print_dump(mp->ml_right); +} diff --git a/usr.bin/size/Makefile b/usr.bin/size/Makefile new file mode 100644 index 0000000..3ad91be --- /dev/null +++ b/usr.bin/size/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= size + +.include diff --git a/usr.bin/size/size.1 b/usr.bin/size/size.1 new file mode 100644 index 0000000..5f3b2fa --- /dev/null +++ b/usr.bin/size/size.1 @@ -0,0 +1,60 @@ +.\" Copyright (c) 1990, 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. +.\" +.\" @(#)size.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt SIZE 1 +.Os +.Sh NAME +.Nm size +.Nd display object file segment sizes (text, data and bss) +.Sh SYNOPSIS +.Nm size +.Op Ar object_file ... +.Sh DESCRIPTION +.Nm Size +displays the text, data and bss segment sizes of the specified +.Ar object_file +in bytes (in decimal), and the sum of the three segments (in +decimal and hexadecimal). +If no +.Ar object_file +is specified +.Nm +attempts to report on the file +.Pa a.out . +.Sh SEE ALSO +.Xr a.out 5 +.Sh HISTORY +A +.Nm size +command appeared in Version 6 AT&T Unix. diff --git a/usr.bin/size/size.c b/usr.bin/size/size.c new file mode 100644 index 0000000..674c3c8 --- /dev/null +++ b/usr.bin/size/size.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)size.c 8.2 (Berkeley) 12/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void err __P((const char *, ...)); +int show __P((int, char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, eval; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + eval = 0; + if (*argv) + do { + eval |= show(argc, *argv); + } while (*++argv); + else + eval |= show(1, "a.out"); + exit(eval); +} + +int +show(count, name) + int count; + char *name; +{ + static int first = 1; + struct exec head; + u_long total; + int fd; + + if ((fd = open(name, O_RDONLY, 0)) < 0) { + err("%s: %s", name, strerror(errno)); + return (1); + } + if (read(fd, &head, sizeof(head)) != sizeof(head) || N_BADMAG(head)) { + (void)close(fd); + err("%s: not in a.out format", name); + return (1); + } + (void)close(fd); + + if (first) { + first = 0; + (void)printf("text\tdata\tbss\tdec\thex\n"); + } + total = head.a_text + head.a_data + head.a_bss; + (void)printf("%lu\t%lu\t%lu\t%lu\t%lx", head.a_text, head.a_data, + head.a_bss, total, total); + if (count > 1) + (void)printf("\t%s", name); + (void)printf("\n"); + return (0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: size [file ...]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "size: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); +} diff --git a/usr.bin/soelim/Makefile b/usr.bin/soelim/Makefile new file mode 100644 index 0000000..8f86a63 --- /dev/null +++ b/usr.bin/soelim/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= soelim + +.include diff --git a/usr.bin/soelim/soelim.1 b/usr.bin/soelim/soelim.1 new file mode 100644 index 0000000..68575aa --- /dev/null +++ b/usr.bin/soelim/soelim.1 @@ -0,0 +1,88 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)soelim.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt SOELIM 1 +.Os BSD 3 +.Sh NAME +.Nm soelim +.Nd eliminate \&.so's from nroff input +.Sh SYNOPSIS +.Nm soelim +.Op Ar file ... +.Sh DESCRIPTION +.Nm Soelim +reads the specified files or the standard input and performs the textual +inclusion implied by the +.Xr nroff 1 +directives of the form: +.Pp +.Dl \&.so somefile +.Pp +The directives need to appear at the beginning of input lines. +This is useful since programs such as +.Xr tbl 1 +do not normally do this; it allows the placement of individual tables +in separate files to be run as a part of a large document. +.Pp +An argument consisting of a single minus +.Ql Fl +is taken to be +a file name corresponding to the standard input. +.Pp +Note that inclusion can be suppressed by using +.Ql \e' +instead of +.Ql \e. , +i.e. +.Pp +.Dl \'so /usr/lib/tmac.s +.Pp +A sample usage of +.Nm soelim +would be +.Pp +.Bd -literal -offset indent -compact +soelim exum?.n \&| tbl \&| nroff \-ms \&| col \&| lpr +.Ed +.Sh SEE ALSO +.Xr colcrt 1 , +.Xr more 1 +.Sh BUGS +The format of the source commands must involve no strangeness \- +exactly one blank must precede and no blanks follow the file name. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/soelim/soelim.c b/usr.bin/soelim/soelim.c new file mode 100644 index 0000000..fab07c3 --- /dev/null +++ b/usr.bin/soelim/soelim.c @@ -0,0 +1,160 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)soelim.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +/* + * soelim - a filter to process n/troff input eliminating .so's + * + * Author: Bill Joy UCB July 8, 1977 + * + * This program eliminates .so's from a n/troff input stream. + * It can be used to prepare safe input for submission to the + * phototypesetter since the software supporting the operator + * doesn't let him do chdir. + * + * This is a kludge and the operator should be given the + * ability to do chdir. + * + * This program is more generally useful, it turns out, because + * the program tbl doesn't understand ".so" directives. + */ +#define STDIN_NAME "-" + +main(argc, argv) + int argc; + char *argv[]; +{ + + argc--; + argv++; + if (argc == 0) { + (void)process(STDIN_NAME); + exit(0); + } + do { + (void)process(argv[0]); + argv++; + argc--; + } while (argc > 0); + exit(0); +} + +int process(file) + char *file; +{ + register char *cp; + register int c; + char fname[BUFSIZ]; + FILE *soee; + int isfile; + + if (!strcmp(file, STDIN_NAME)) { + soee = stdin; + } else { + soee = fopen(file, "r"); + if (soee == NULL) { + perror(file); + return(-1); + } + } + for (;;) { + c = getc(soee); + if (c == EOF) + break; + if (c != '.') + goto simple; + c = getc(soee); + if (c != 's') { + putchar('.'); + goto simple; + } + c = getc(soee); + if (c != 'o') { + printf(".s"); + goto simple; + } + do + c = getc(soee); + while (c == ' ' || c == '\t'); + cp = fname; + isfile = 0; + for (;;) { + switch (c) { + + case ' ': + case '\t': + case '\n': + case EOF: + goto donename; + + default: + *cp++ = c; + c = getc(soee); + isfile++; + continue; + } + } +donename: + if (cp == fname) { + printf(".so"); + goto simple; + } + *cp = 0; + if (process(fname) < 0) + if (isfile) + printf(".so %s\n", fname); + continue; +simple: + if (c == EOF) + break; + putchar(c); + if (c != '\n') { + c = getc(soee); + goto simple; + } + } + if (soee != stdin) { + fclose(soee); + } + return(0); +} diff --git a/usr.bin/split/Makefile b/usr.bin/split/Makefile new file mode 100644 index 0000000..93048f7 --- /dev/null +++ b/usr.bin/split/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= split + +.include diff --git a/usr.bin/split/split.1 b/usr.bin/split/split.1 new file mode 100644 index 0000000..34f3c07 --- /dev/null +++ b/usr.bin/split/split.1 @@ -0,0 +1,99 @@ +.\" Copyright (c) 1990, 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. +.\" +.\" @(#)split.1 8.3 (Berkeley) 4/16/94 +.\" +.Dd April 16, 1994 +.Dt SPLIT 1 +.Os +.Sh NAME +.Nm split +.Nd split a file into pieces +.Sh SYNOPSIS +.Nm split +.Op Fl b Ar byte_count[k|m] +.Op Fl l Ar line_count +.Op Ar file Op Ar name +.Sh DESCRIPTION +The +.Nm split +utility reads the given +.Ar file +(or standard input if no file is specified) +and breaks it up into files of 1000 lines each. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b +Create smaller files +.Ar byte_count +bytes in length. +If +.Dq Li k +is appended to the number, the file is split into +.Ar byte_count +kilobyte pieces. +If +.Dq Li m +is appended to the number, the file is split into +.Ar byte_count +megabyte pieces. +.It Fl l +Create smaller files +.Ar n +lines in length. +.El +.Pp +If additional arguments are specified, the first is used as the name +of the input file which is to be split. +If a second additional argument is specified, it is used as a prefix +for the names of the files into which the file is split. +In this case, each file into which the file is split is named by the +prefix followed by a lexically ordered suffix in the range of +.Dq Li aa-zz . +.Pp +If the +.Ar name +argument is not specified, the file is split into lexically ordered +files named in the range of +.Dq Li xaa-zzz . +.Sh BUGS +For historical reasons, if you specify +.Ar name , +.Nm split +can only create 676 separate +files. +The default naming convention allows 2028 separate files. +.Sh HISTORY +A +.Nm split +command appeared in +.At v6 . diff --git a/usr.bin/split/split.c b/usr.bin/split/split.c new file mode 100644 index 0000000..198532b --- /dev/null +++ b/usr.bin/split/split.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)split.c 8.2 (Berkeley) 4/16/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DEFLINE 1000 /* Default num lines per file. */ + +long bytecnt; /* Byte count to split on. */ +long numlines; /* Line count to split on. */ +int file_open; /* If a file open. */ +int ifd = -1, ofd = -1; /* Input/output file descriptors. */ +char bfr[MAXBSIZE]; /* I/O buffer. */ +char fname[MAXPATHLEN]; /* File name prefix. */ + +void newfile __P((void)); +void split1 __P((void)); +void split2 __P((void)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch; + char *ep, *p; + + while ((ch = getopt(argc, argv, "-0123456789b:l:")) != EOF) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * Undocumented kludge: split was originally designed + * to take a number after a dash. + */ + if (numlines == 0) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + numlines = strtol(++p, &ep, 10); + else + numlines = + strtol(argv[optind] + 1, &ep, 10); + if (numlines <= 0 || *ep) + errx(1, + "%s: illegal line count.", optarg); + } + break; + case '-': /* Undocumented: historic stdin flag. */ + if (ifd != -1) + usage(); + ifd = 0; + break; + case 'b': /* Byte count. */ + if ((bytecnt = strtol(optarg, &ep, 10)) <= 0 || + *ep != '\0' && *ep != 'k' && *ep != 'm') + errx(1, "%s: illegal byte count.", optarg); + if (*ep == 'k') + bytecnt *= 1024; + else if (*ep == 'm') + bytecnt *= 1048576; + break; + case 'l': /* Line count. */ + if (numlines != 0) + usage(); + if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *p) + errx(1, "%s: illegal line count.", optarg); + break; + default: + usage(); + } + argv += optind; + argc -= optind; + + if (*argv != NULL) + if (ifd == -1) { /* Input file. */ + if ((ifd = open(*argv, O_RDONLY, 0)) < 0) + err(1, "%s", *argv); + ++argv; + } + if (*argv != NULL) /* File name prefix. */ + (void)strcpy(fname, *argv++); + if (*argv != NULL) + usage(); + + if (numlines == 0) + numlines = DEFLINE; + else if (bytecnt) + usage(); + + if (ifd == -1) /* Stdin by default. */ + ifd = 0; + + if (bytecnt) { + split1(); + exit (0); + } + split2(); + exit(0); +} + +/* + * split1 -- + * Split the input by bytes. + */ +void +split1() +{ + long bcnt; + int dist, len; + char *C; + + for (bcnt = 0;;) + switch (len = read(ifd, bfr, MAXBSIZE)) { + case 0: + exit(0); + case -1: + err(1, "read"); + /* NOTREACHED */ + default: + if (!file_open) { + newfile(); + file_open = 1; + } + if (bcnt + len >= bytecnt) { + dist = bytecnt - bcnt; + if (write(ofd, bfr, dist) != dist) + err(1, "write"); + len -= dist; + for (C = bfr + dist; len >= bytecnt; + len -= bytecnt, C += bytecnt) { + newfile(); + if (write(ofd, + C, (int)bytecnt) != bytecnt) + err(1, "write"); + } + if (len) { + newfile(); + if (write(ofd, C, len) != len) + err(1, "write"); + } else + file_open = 0; + bcnt = len; + } else { + bcnt += len; + if (write(ofd, bfr, len) != len) + err(1, "write"); + } + } +} + +/* + * split2 -- + * Split the input by lines. + */ +void +split2() +{ + long lcnt; + int len, bcnt; + char *Ce, *Cs; + + for (lcnt = 0;;) + switch (len = read(ifd, bfr, MAXBSIZE)) { + case 0: + exit(0); + case -1: + err(1, "read"); + /* NOTREACHED */ + default: + if (!file_open) { + newfile(); + file_open = 1; + } + for (Cs = Ce = bfr; len--; Ce++) + if (*Ce == '\n' && ++lcnt == numlines) { + bcnt = Ce - Cs + 1; + if (write(ofd, Cs, bcnt) != bcnt) + err(1, "write"); + lcnt = 0; + Cs = Ce + 1; + if (len) + newfile(); + else + file_open = 0; + } + if (Cs < Ce) { + bcnt = Ce - Cs; + if (write(ofd, Cs, bcnt) != bcnt) + err(1, "write"); + } + } +} + +/* + * newfile -- + * Open a new output file. + */ +void +newfile() +{ + static long fnum; + static int defname; + static char *fpnt; + + if (ofd == -1) { + if (fname[0] == '\0') { + fname[0] = 'x'; + fpnt = fname + 1; + defname = 1; + } else { + fpnt = fname + strlen(fname); + defname = 0; + } + ofd = fileno(stdout); + } + /* + * Hack to increase max files; original code wandered through + * magic characters. Maximum files is 3 * 26 * 26 == 2028 + */ +#define MAXFILES 676 + if (fnum == MAXFILES) { + if (!defname || fname[0] == 'z') + errx(1, "too many files."); + ++fname[0]; + fnum = 0; + } + fpnt[0] = fnum / 26 + 'a'; + fpnt[1] = fnum % 26 + 'a'; + ++fnum; + if (!freopen(fname, "w", stdout)) + err(1, "%s", fname); +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: split [-b byte_count] [-l line_count] [file [prefix]]\n"); + exit(1); +} diff --git a/usr.bin/strings/Makefile b/usr.bin/strings/Makefile new file mode 100644 index 0000000..87f557d --- /dev/null +++ b/usr.bin/strings/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= strings + +.include diff --git a/usr.bin/strings/strings.1 b/usr.bin/strings/strings.1 new file mode 100644 index 0000000..ceeae10 --- /dev/null +++ b/usr.bin/strings/strings.1 @@ -0,0 +1,96 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)strings.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt STRINGS 1 +.Os BSD 3 +.Sh NAME +.Nm strings +.Nd find printable strings in a file +.Sh SYNOPSIS +.Nm strings +.Op Fl afo +.Op Fl n Ar number +.Op Ar file ... +.Sh DESCRIPTION +.Nm Strings +displays the sequences of printable characters in each of the specified +files, or in the standard input, by default. +By default, a sequence must be at least four characters in length +before being displayed. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +By default, +.Nm strings +only searches the text and data segments of object files. +The +.Fl a +option causes +.Nm strings +to search the entire object file. +.It Fl f +Each string is preceded by the name of the file +in which it was found. +.It Fl n +Specifies the minimum number of characters in a sequence to be +.Ar number , +instead of four. +.It Fl o +Each string is preceded by its decimal offset in the +file. +.El +.Pp +.Nm Strings +is useful for identifying random binaries, among other things. +.Sh SEE ALSO +.Xr hexdump 1 +.Sh BUGS +The algorithm for identifying strings is extremely primitive. +In particular, machine code instructions on certain architectures +can resemble sequences of ASCII bytes, which +will fool the algorithm. +.Sh COMPATIBILITY +Historic implementations of +.Nm +only search the initialized data portion of the object file. +This was reasonable as strings were normally stored there. +Given new compiler technology which installs strings in the +text portion of the object file, the default behavior was +changed. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/strings/strings.c b/usr.bin/strings/strings.c new file mode 100644 index 0000000..398ccac --- /dev/null +++ b/usr.bin/strings/strings.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1980, 1987, 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 copyright[] = +"@(#) Copyright (c) 1980, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)strings.c 8.2 (Berkeley) 1/28/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEF_LEN 4 /* default minimum string length */ +#define ISSTR(ch) (isascii(ch) && (isprint(ch) || ch == '\t')) + +typedef struct exec EXEC; /* struct exec cast */ + +static long foff; /* offset in the file */ +static int hcnt, /* head count */ + head_len, /* length of header */ + read_len; /* length to read */ +static u_char hbfr[sizeof(EXEC)]; /* buffer for struct exec */ + +static void usage(); + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + register int ch, cnt; + register u_char *C; + EXEC *head; + int exitcode, minlen; + short asdata, oflg, fflg; + u_char *bfr; + char *file, *p; + + /* + * for backward compatibility, allow '-' to specify 'a' flag; no + * longer documented in the man page or usage string. + */ + asdata = exitcode = fflg = oflg = 0; + minlen = -1; + while ((ch = getopt(argc, argv, "-0123456789an:of")) != EOF) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: strings was originally designed to take + * a number after a dash. + */ + if (minlen == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + minlen = atoi(++p); + else + minlen = atoi(argv[optind] + 1); + } + break; + case '-': + case 'a': + asdata = 1; + break; + case 'f': + fflg = 1; + break; + case 'n': + minlen = atoi(optarg); + break; + case 'o': + oflg = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (minlen == -1) + minlen = DEF_LEN; + else { + (void)fprintf(stderr, "strings: length less than 1\n"); + exit (1); + } + + if (!(bfr = malloc((u_int)minlen))) { + (void)fprintf(stderr, "strings: %s\n", strerror(errno)); + exit(1); + } + bfr[minlen] = '\0'; + file = "stdin"; + do { + if (*argv) { + file = *argv++; + if (!freopen(file, "r", stdin)) { + (void)fprintf(stderr, + "strings: %s: %s\n", file, strerror(errno)); + exitcode = 1; + goto nextfile; + } + } + foff = 0; +#define DO_EVERYTHING() {read_len = -1; head_len = 0; goto start;} + read_len = -1; + if (asdata) + DO_EVERYTHING() + else { + head = (EXEC *)hbfr; + if ((head_len = + read(fileno(stdin), head, sizeof(EXEC))) == -1) + DO_EVERYTHING() + if (head_len == sizeof(EXEC) && !N_BADMAG(*head)) { + foff = N_TXTOFF(*head); + if (fseek(stdin, foff, SEEK_SET) == -1) + DO_EVERYTHING() + read_len = head->a_text + head->a_data; + head_len = 0; + } + else + hcnt = 0; + } +start: + for (cnt = 0; (ch = getch()) != EOF;) { + if (ISSTR(ch)) { + if (!cnt) + C = bfr; + *C++ = ch; + if (++cnt < minlen) + continue; + if (fflg) + printf("%s:", file); + if (oflg) + printf("%07ld %s", + foff - minlen, (char *)bfr); + else + printf("%s", bfr); + while ((ch = getch()) != EOF && ISSTR(ch)) + putchar((char)ch); + putchar('\n'); + } + cnt = 0; + } +nextfile: ; + } while (*argv); + exit(exitcode); +} + +/* + * getch -- + * get next character from wherever + */ +getch() +{ + ++foff; + if (head_len) { + if (hcnt < head_len) + return((int)hbfr[hcnt++]); + head_len = 0; + } + if (read_len == -1 || read_len-- > 0) + return(getchar()); + return(EOF); +} + +static void +usage() +{ + (void)fprintf(stderr, + "usage: strings [-afo] [-n length] [file ... ]\n"); + exit(1); +} diff --git a/usr.bin/strip/Makefile b/usr.bin/strip/Makefile new file mode 100644 index 0000000..aedea50 --- /dev/null +++ b/usr.bin/strip/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= strip + +install: maninstall + install -c -o ${BINOWN} -g ${BINOWN} -m ${BINMODE} strip \ + ${DESTDIR}${BINDIR} + ./strip ${DESTDIR}${BINDIR}/strip + rm -f ./strip + +.include diff --git a/usr.bin/strip/strip.1 b/usr.bin/strip/strip.1 new file mode 100644 index 0000000..b131004 --- /dev/null +++ b/usr.bin/strip/strip.1 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)strip.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt STRIP 1 +.Os +.Sh NAME +.Nm strip +.Nd remove unnecessary information from executable files +.Sh SYNOPSIS +.Nm strip +.Op Fl d +.Ar file ... +.Sh DESCRIPTION +The +.Nm strip +utility +deletes the relocation information and symbol table used by +assemblers, loaders and debuggers. +This significantly +decreases the size of the installed binaries and saves disk space. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Delete only debugging and empty symbols. +.El +.Pp +.Nm Strip +exits 0 on success and 1 if an error occurred. +.Sh SEE ALSO +.Xr cc 1 , +.Xr ld 1 , +.Xr stab 5 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/strip/strip.c b/usr.bin/strip/strip.c new file mode 100644 index 0000000..9de05f7 --- /dev/null +++ b/usr.bin/strip/strip.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)strip.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct exec EXEC; +typedef struct nlist NLIST; + +#define strx n_un.n_strx + +void err __P((int, const char *fmt, ...)); +void s_stab __P((const char *, int, EXEC *)); +void s_sym __P((const char *, int, EXEC *)); +void usage __P((void)); + +int eval; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int fd, nb; + EXEC head; + void (*sfcn)__P((const char *, int, EXEC *)); + int ch; + char *fn; + + sfcn = s_sym; + while ((ch = getopt(argc, argv, "d")) != EOF) + switch(ch) { + case 'd': + sfcn = s_stab; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + while (fn = *argv++) { + if ((fd = open(fn, O_RDWR)) < 0 || + (nb = read(fd, &head, sizeof(EXEC))) == -1) { + err(0, "%s: %s", fn, strerror(errno)); + continue; + } + if (nb != sizeof(EXEC) || N_BADMAG(head)) { + err(0, "%s: %s", fn, strerror(EFTYPE)); + continue; + } + sfcn(fn, fd, &head); + if (close(fd)) + err(0, "%s: %s", fn, strerror(errno)); + } + exit(eval); +} + +void +s_sym(fn, fd, ep) + const char *fn; + int fd; + register EXEC *ep; +{ + register off_t fsize; + + /* If no symbols or data/text relocation info, quit. */ + if (!ep->a_syms && !ep->a_trsize && !ep->a_drsize) + return; + + /* + * New file size is the header plus text and data segments. + */ + fsize = N_DATOFF(*ep) + ep->a_data; + + /* Set symbol size and relocation info values to 0. */ + ep->a_syms = ep->a_trsize = ep->a_drsize = 0; + + /* Rewrite the header and truncate the file. */ + if (lseek(fd, (off_t)0, SEEK_SET) == -1 || + write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) || + ftruncate(fd, fsize)) + err(0, "%s: %s", fn, strerror(errno)); +} + +void +s_stab(fn, fd, ep) + const char *fn; + int fd; + EXEC *ep; +{ + register int cnt, len; + register char *nstr, *nstrbase, *p, *strbase; + register NLIST *sym, *nsym; + struct stat sb; + NLIST *symbase; + + /* Quit if no symbols. */ + if (ep->a_syms == 0) + return; + + /* Stat the file. */ + if (fstat(fd, &sb) < 0) { + err(0, "%s: %s", fn, strerror(errno)); + return; + } + + /* Check size. */ + if (sb.st_size > SIZE_T_MAX) { + err(0, "%s: %s", fn, strerror(EFBIG)); + return; + } + + /* Map the file. */ + if ((ep = (EXEC *)mmap(NULL, (size_t)sb.st_size, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)-1) { + err(0, "%s: %s", fn, strerror(errno)); + return; + } + + /* + * Initialize old and new symbol pointers. They both point to the + * beginning of the symbol table in memory, since we're deleting + * entries. + */ + sym = nsym = symbase = (NLIST *)((char *)ep + N_SYMOFF(*ep)); + + /* + * Allocate space for the new string table, initialize old and + * new string pointers. Handle the extra long at the beginning + * of the string table. + */ + strbase = (char *)ep + N_STROFF(*ep); + if ((nstrbase = malloc((u_int)*(u_long *)strbase)) == NULL) + err(1, "%s", strerror(errno)); + nstr = nstrbase + sizeof(u_long); + + /* + * Read through the symbol table. For each non-debugging symbol, + * copy it and save its string in the new string table. Keep + * track of the number of symbols. + */ + for (cnt = ep->a_syms / sizeof(NLIST); cnt--; ++sym) + if (!(sym->n_type & N_STAB) && sym->strx) { + *nsym = *sym; + nsym->strx = nstr - nstrbase; + p = strbase + sym->strx; + len = strlen(p) + 1; + bcopy(p, nstr, len); + nstr += len; + ++nsym; + } + + /* Fill in new symbol table size. */ + ep->a_syms = (nsym - symbase) * sizeof(NLIST); + + /* Fill in the new size of the string table. */ + *(u_long *)nstrbase = len = nstr - nstrbase; + + /* + * Copy the new string table into place. Nsym should be pointing + * at the address past the last symbol entry. + */ + bcopy(nstrbase, (void *)nsym, len); + + /* Truncate to the current length. */ + if (ftruncate(fd, (char *)nsym + len - (char *)ep)) + err(0, "%s: %s", fn, strerror(errno)); + munmap((caddr_t)ep, (size_t)sb.st_size); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: strip [-d] file ...\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(int fatal, const char *fmt, ...) +#else +err(fatal, fmt, va_alist) + int fatal; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "strip: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (fatal) + exit(1); + eval = 1; +} diff --git a/usr.bin/su/Makefile b/usr.bin/su/Makefile new file mode 100644 index 0000000..e3e023a --- /dev/null +++ b/usr.bin/su/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 7/19/93 + +PROG= su +CFLAGS+=-DKERBEROS +DPADD= ${LIBKRB} ${LIBDES} +LDADD= -lkrb -ldes +BINOWN= root +BINMODE=4555 +INSTALLFLAGS=-fschg + +.include diff --git a/usr.bin/su/su.1 b/usr.bin/su/su.1 new file mode 100644 index 0000000..ea9edcf --- /dev/null +++ b/usr.bin/su/su.1 @@ -0,0 +1,172 @@ +.\" Copyright (c) 1988, 1990, 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. +.\" +.\" @(#)su.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt SU 1 +.Os +.Sh NAME +.Nm su +.Nd substitute user identity +.Sh SYNOPSIS +.Nm su +.Op Fl Kflm +.Op Ar login +.Sh DESCRIPTION +.Nm Su +requests the Kerberos password for +.Ar login +(or for +.Dq Ar login Ns .root , +if no login is provided), and switches to +that user and group ID after obtaining a Kerberos ticket granting ticket. +A shell is then executed. +.Nm Su +will resort to the local password file to find the password for +.Ar login +if there is a Kerberos error. +If +.Nm su +is executed by root, no password is requested and a shell +with the appropriate user ID is executed; no additional Kerberos tickets +are obtained. +.Pp +By default, the environment is unmodified with the exception of +.Ev USER , +.Ev HOME , +and +.Ev SHELL . +.Ev HOME +and +.Ev SHELL +are set to the target login's default values. +.Ev USER +is set to the target login, unless the target login has a user ID of 0, +in which case it is unmodified. +The invoked shell is the target login's. +This is the traditional behavior of +.Nm su . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl K +Do not attempt to use Kerberos to authenticate the user. +.It Fl f +If the invoked shell is +.Xr csh 1 , +this option prevents it from reading the +.Dq Pa .cshrc +file. +.It Fl l +Simulate a full login. +The environment is discarded except for +.Ev HOME , +.Ev SHELL , +.Ev PATH , +.Ev TERM , +and +.Ev USER . +.Ev HOME +and +.Ev SHELL +are modified as above. +.Ev USER +is set to the target login. +.Ev PATH +is set to +.Dq Pa /bin:/usr/bin . +.Ev TERM +is imported from your current environment. +The invoked shell is the target login's, and +.Nm su +will change directory to the target login's home directory. +.It Fl m +Leave the environment unmodified. +The invoked shell is your login shell, and no directory changes are made. +As a security precaution, if the target user's shell is a non-standard +shell (as defined by +.Xr getusershell 3 ) +and the caller's real uid is +non-zero, +.Nm su +will fail. +.El +.Pp +The +.Fl l +and +.Fl m +options are mutually exclusive; the last one specified +overrides any previous ones. +.Pp +Only users in group 0 (normally +.Dq wheel ) +can +.Nm su +to +.Dq root . +.Pp +By default (unless the prompt is reset by a startup file) the super-user +prompt is set to +.Dq Sy \&# +to remind one of its awesome power. +.Sh SEE ALSO +.Xr csh 1 , +.Xr login 1 , +.Xr sh 1 , +.Xr kinit 1 , +.Xr kerberos 1 , +.Xr passwd 5 , +.Xr group 5 , +.Xr environ 7 +.Sh ENVIRONMENT +Environment variables used by +.Nm su : +.Bl -tag -width HOME +.It Ev HOME +Default home directory of real user ID unless modified as +specified above. +.It Ev PATH +Default search path of real user ID unless modified as specified above. +.It Ev TERM +Provides terminal type which may be retained for the substituted +user ID. +.It Ev USER +The user ID is always the effective ID (the target user ID) after an +.Nm su +unless the user ID is 0 (root). +.El +.Sh HISTORY +A +.Nm +command appeared in +.At v7 . diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c new file mode 100644 index 0000000..f06ef2f --- /dev/null +++ b/usr.bin/su/su.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include +#include + +#define ARGSTR "-Kflm" + +int use_kerberos = 1; +#else +#define ARGSTR "-flm" +#endif + +char *ontty __P((void)); +int chshell __P((char *)); + +int +main(argc, argv) + int argc; + char **argv; +{ + extern char **environ; + struct passwd *pwd; + char *p, **g, *user, *shell, *username, *cleanenv[2], *nargv[4], **np; + struct group *gr; + uid_t ruid; + int asme, ch, asthem, fastlogin, prio; + enum { UNSET, YES, NO } iscsh = UNSET; + char shellbuf[MAXPATHLEN]; + + np = &nargv[3]; + *np-- = NULL; + asme = asthem = fastlogin = 0; + while ((ch = getopt(argc, argv, ARGSTR)) != EOF) + switch((char)ch) { +#ifdef KERBEROS + 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; + break; + case '?': + default: + (void)fprintf(stderr, "usage: su [%s] [login]\n", + ARGSTR); + exit(1); + } + argv += optind; + + errno = 0; + prio = getpriority(PRIO_PROCESS, 0); + if (errno) + prio = 0; + (void)setpriority(PRIO_PROCESS, 0, -2); + openlog("su", LOG_CONS, 0); + + /* get current login name and shell */ + ruid = getuid(); + username = getlogin(); + if (username == NULL || (pwd = getpwnam(username)) == NULL || + pwd->pw_uid != ruid) + pwd = getpwuid(ruid); + if (pwd == NULL) + errx(1, "who are you?"); + username = strdup(pwd->pw_name); + if (username == NULL) + err(1, NULL); + if (asme) + if (pwd->pw_shell && *pwd->pw_shell) + shell = strcpy(shellbuf, pwd->pw_shell); + else { + shell = _PATH_BSHELL; + iscsh = NO; + } + + /* 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); + } + + if (ruid) { +#ifdef KERBEROS + if (!use_kerberos || kerberos(username, user, pwd->pw_uid)) +#endif + { + /* only allow those in group zero to su to root. */ + if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) + for (g = gr->gr_mem;; ++g) { + if (!*g) + errx(1, + "you are not in the correct group to su %s.", + user); + if (strcmp(username, *g) == 0) + break; + } + /* if target requires a password, verify it */ + if (*pwd->pw_passwd) { + p = getpass("Password:"); + if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { + fprintf(stderr, "Sorry\n"); + syslog(LOG_AUTH|LOG_WARNING, + "BAD SU %s to %s%s", username, + user, ontty()); + exit(1); + } + } + } + } + + if (asme) { + /* if asme and non-standard target shell, must be root */ + if (!chshell(pwd->pw_shell) && ruid) + errx(1, "permission denied (shell)."); + } else if (pwd->pw_shell && *pwd->pw_shell) { + shell = pwd->pw_shell; + iscsh = UNSET; + } else { + shell = _PATH_BSHELL; + iscsh = NO; + } + + /* if we're forking a csh, we want to slightly muck the args */ + if (iscsh == UNSET) { + if (p = strrchr(shell, '/')) + ++p; + else + p = shell; + iscsh = strcmp(p, "csh") ? NO : YES; + } + + /* set permissions */ + if (setgid(pwd->pw_gid) < 0) + err(1, "setgid"); + if (initgroups(user, pwd->pw_gid)) + errx(1, "initgroups failed"); + if (setuid(pwd->pw_uid) < 0) + err(1, "setuid"); + + if (!asme) { + if (asthem) { + p = getenv("TERM"); + cleanenv[0] = _PATH_DEFPATH; + cleanenv[1] = NULL; + environ = cleanenv; + (void)setenv("TERM", p, 1); + if (chdir(pwd->pw_dir) < 0) + errx(1, "no directory"); + } + if (asthem || pwd->pw_uid) + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("HOME", pwd->pw_dir, 1); + (void)setenv("SHELL", shell, 1); + } + + if (iscsh == YES) { + if (fastlogin) + *np-- = "-f"; + if (asme) + *np-- = "-m"; + } + + /* csh strips the first character... */ + *np = asthem ? "-su" : iscsh == YES ? "_su" : "su"; + + if (ruid != 0) + syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s", + username, user, ontty()); + + (void)setpriority(PRIO_PROCESS, 0, prio); + + execv(shell, np); + err(1, "%s", shell); +} + +int +chshell(sh) + char *sh; +{ + char *cp; + + while ((cp = getusershell()) != NULL) + if (strcmp(cp, sh) == 0) + return (1); + return (0); +} + +char * +ontty() +{ + char *p; + static char buf[MAXPATHLEN + 4]; + + buf[0] = 0; + if (p = ttyname(STDERR_FILENO)) + snprintf(buf, sizeof(buf), " on %s", p); + return (buf); +} + +#ifdef KERBEROS +kerberos(username, user, uid) + char *username, *user; + int uid; +{ + extern char *krb_err_txt[]; + KTEXT_ST ticket; + AUTH_DAT authdata; + struct hostent *hp; + char *p; + int kerno; + u_long faddr; + char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN]; + char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; + char *krb_get_phost(); + + if (krb_get_lrealm(lrealm, 1) != KSUCCESS) + return (1); + if (koktologin(username, lrealm, user) && !uid) { + warnx("kerberos: not in %s's ACL.", user); + return (1); + } + (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid()); + + (void)setenv("KRBTKFILE", krbtkfile, 1); + (void)krb_set_tkt_string(krbtkfile); + /* + * Set real as well as effective ID to 0 for the moment, + * to make the kerberos library do the right thing. + */ + if (setuid(0) < 0) { + warn("setuid"); + return (1); + } + + /* + * Little trick here -- if we are su'ing to root, + * we need to get a ticket for "xxx.root", where xxx represents + * the name of the person su'ing. Otherwise (non-root case), + * we need to get a ticket for "yyy.", where yyy represents + * the name of the person being su'd to, and the instance is null + * + * We should have a way to set the ticket lifetime, + * with a system default for root. + */ + kerno = krb_get_pw_in_tkt((uid == 0 ? username : user), + (uid == 0 ? "root" : ""), lrealm, + "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0); + + if (kerno != KSUCCESS) { + if (kerno == KDC_PR_UNKNOWN) { + warnx("kerberos: principal unknown: %s.%s@%s", + (uid == 0 ? username : user), + (uid == 0 ? "root" : ""), lrealm); + return (1); + } + warnx("kerberos: unable to su: %s", krb_err_txt[kerno]); + syslog(LOG_NOTICE|LOG_AUTH, + "BAD Kerberos SU: %s to %s%s: %s", + username, user, ontty(), krb_err_txt[kerno]); + return (1); + } + + if (chown(krbtkfile, uid, -1) < 0) { + warn("chown"); + (void)unlink(krbtkfile); + return (1); + } + + (void)setpriority(PRIO_PROCESS, 0, -2); + + if (gethostname(hostname, sizeof(hostname)) == -1) { + warn("gethostname"); + dest_tkt(); + return (1); + } + + (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost)); + savehost[sizeof(savehost) - 1] = '\0'; + + kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); + + if (kerno == KDC_PR_UNKNOWN) { + warnx("Warning: TGT not verified."); + syslog(LOG_NOTICE|LOG_AUTH, + "%s to %s%s, TGT not verified (%s); %s.%s not registered?", + username, user, ontty(), krb_err_txt[kerno], + "rcmd", savehost); + } else if (kerno != KSUCCESS) { + warnx("Unable to use TGT: %s", krb_err_txt[kerno]); + syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", + username, user, ontty(), krb_err_txt[kerno]); + dest_tkt(); + return (1); + } else { + if (!(hp = gethostbyname(hostname))) { + warnx("can't get addr of %s", hostname); + dest_tkt(); + return (1); + } + memmove((char *)&faddr, (char *)hp->h_addr, sizeof(faddr)); + + if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, + &authdata, "")) != KSUCCESS) { + warnx("kerberos: unable to verify rcmd ticket: %s\n", + krb_err_txt[kerno]); + syslog(LOG_NOTICE|LOG_AUTH, + "failed su: %s to %s%s: %s", username, + user, ontty(), krb_err_txt[kerno]); + dest_tkt(); + return (1); + } + } + return (0); +} + +koktologin(name, realm, toname) + char *name, *realm, *toname; +{ + AUTH_DAT *kdata; + AUTH_DAT kdata_st; + + kdata = &kdata_st; + memset((char *)kdata, 0, sizeof(*kdata)); + (void)strcpy(kdata->pname, name); + (void)strcpy(kdata->pinst, + ((strcmp(toname, "root") == 0) ? "root" : "")); + (void)strcpy(kdata->prealm, realm); + return (kuserok(kdata, toname)); +} +#endif diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile new file mode 100644 index 0000000..67e3624 --- /dev/null +++ b/usr.bin/systat/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= systat +CFLAGS+=-I/sys -I${.CURDIR}/../vmstat +SRCS= cmds.c cmdtab.c disks.c fetch.c iostat.c keyboard.c vmstat.c main.c \ + mbufs.c netcmds.c netstat.c pigs.c swap.c +LDADD= -lcurses -ltermcap -lm -lkvm +DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} +BINGRP= kmem +BINMODE=2555 + +.include diff --git a/usr.bin/systat/cmds.c b/usr.bin/systat/cmds.c new file mode 100644 index 0000000..4987c2c --- /dev/null +++ b/usr.bin/systat/cmds.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +void +command(cmd) + char *cmd; +{ + register struct cmdtab *p; + register char *cp; + int interval, omask; + + omask = sigblock(sigmask(SIGALRM)); + for (cp = cmd; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (*cmd == '\0') + return; + for (; *cp && isspace(*cp); cp++) + ; + if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "q") == 0) + die(0); + if (strcmp(cmd, "load") == 0) { + load(); + goto done; + } + if (strcmp(cmd, "stop") == 0) { + alarm(0); + mvaddstr(CMDLINE, 0, "Refresh disabled."); + clrtoeol(); + goto done; + } + if (strcmp(cmd, "help") == 0) { + int col, len; + + move(CMDLINE, col = 0); + for (p = cmdtab; p->c_name; p++) { + len = strlen(p->c_name); + if (col + len > COLS) + break; + addstr(p->c_name); col += len; + if (col + 1 < COLS) + addch(' '); + } + clrtoeol(); + goto done; + } + interval = atoi(cmd); + if (interval <= 0 && + (strcmp(cmd, "start") == 0 || strcmp(cmd, "interval") == 0)) { + interval = *cp ? atoi(cp) : naptime; + if (interval <= 0) { + error("%d: bad interval.", interval); + goto done; + } + } + if (interval > 0) { + alarm(0); + naptime = interval; + display(0); + status(); + goto done; + } + p = lookup(cmd); + if (p == (struct cmdtab *)-1) { + error("%s: Ambiguous command.", cmd); + goto done; + } + if (p) { + if (curcmd == p) + goto done; + alarm(0); + (*curcmd->c_close)(wnd); + wnd = (*p->c_open)(); + if (wnd == 0) { + error("Couldn't open new display"); + wnd = (*curcmd->c_open)(); + if (wnd == 0) { + error("Couldn't change back to previous cmd"); + exit(1); + } + p = curcmd; + } + if ((p->c_flags & CF_INIT) == 0) { + if ((*p->c_init)()) + p->c_flags |= CF_INIT; + else + goto done; + } + curcmd = p; + labels(); + display(0); + status(); + goto done; + } + if (curcmd->c_cmd == 0 || !(*curcmd->c_cmd)(cmd, cp)) + error("%s: Unknown command.", cmd); +done: + sigsetmask(omask); +} + +struct cmdtab * +lookup(name) + register char *name; +{ + register char *p, *q; + register struct cmdtab *c, *found; + register int nmatches, longest; + + longest = 0; + nmatches = 0; + found = (struct cmdtab *) 0; + for (c = cmdtab; p = c->c_name; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmdtab *)-1); + return (found); +} + +void +status() +{ + + error("Showing %s, refresh every %d seconds.", + curcmd->c_name, naptime); +} + +int +prefix(s1, s2) + register char *s1, *s2; +{ + + while (*s1 == *s2) { + if (*s1 == '\0') + return (1); + s1++, s2++; + } + return (*s1 == '\0'); +} diff --git a/usr.bin/systat/cmdtab.c b/usr.bin/systat/cmdtab.c new file mode 100644 index 0000000..71eef34 --- /dev/null +++ b/usr.bin/systat/cmdtab.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "systat.h" +#include "extern.h" + +struct cmdtab cmdtab[] = { + { "pigs", showpigs, fetchpigs, labelpigs, + initpigs, openpigs, closepigs, 0, + CF_LOADAV }, + { "swap", showswap, fetchswap, labelswap, + initswap, openswap, closeswap, 0, + CF_LOADAV }, + { "mbufs", showmbufs, fetchmbufs, labelmbufs, + initmbufs, openmbufs, closembufs, 0, + CF_LOADAV }, + { "iostat", showiostat, fetchiostat, labeliostat, + initiostat, openiostat, closeiostat, cmdiostat, + CF_LOADAV }, + { "vmstat", showkre, fetchkre, labelkre, + initkre, openkre, closekre, cmdkre, + 0 }, + { "netstat", shownetstat, fetchnetstat, labelnetstat, + initnetstat, opennetstat, closenetstat, cmdnetstat, + CF_LOADAV }, + { 0 } +}; +struct cmdtab *curcmd = &cmdtab[0]; diff --git a/usr.bin/systat/disks.c b/usr.bin/systat/disks.c new file mode 100644 index 0000000..f412e30 --- /dev/null +++ b/usr.bin/systat/disks.c @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static void dkselect __P((char *, int, int [])); +static int read_names __P((void)); + +static struct nlist namelist[] = { +#define X_DK_NDRIVE 0 + { "_dk_ndrive" }, +#define X_DK_WPMS 1 + { "_dk_wpms" }, +#ifdef vax +#define X_MBDINIT (X_DK_WPMS+1) + { "_mbdinit" }, +#define X_UBDINIT (X_DK_WPMS+2) + { "_ubdinit" }, +#endif +#ifdef sun +#define X_MBDINIT (X_DK_WPMS+1) + { "_mbdinit" }, +#endif +#ifdef tahoe +#define X_VBDINIT (X_DK_WPMS+1) + { "_vbdinit" }, +#endif +#if defined(hp300) || defined(luna68k) +#define X_HPDINIT (X_DK_WPMS+1) + { "_hp_dinit" }, +#endif +#ifdef mips +#define X_SCSI_DINIT (X_DK_WPMS+1) + { "_scsi_dinit" }, +#endif + { "" }, +}; + +float *dk_mspw; +int dk_ndrive, *dk_select; +char **dr_name; + +#include "names.c" /* XXX */ + +int +dkinit() +{ + register int i; + register char *cp; + static int once = 0; + static char buf[1024]; + + if (once) + return(1); + + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[X_DK_NDRIVE].n_value == 0) { + error("dk_ndrive undefined in kernel"); + return(0); + } + NREAD(X_DK_NDRIVE, &dk_ndrive, LONG); + if (dk_ndrive <= 0) { + error("dk_ndrive=%d according to %s", dk_ndrive, _PATH_UNIX); + return(0); + } + dk_mspw = (float *)calloc(dk_ndrive, sizeof (float)); + { + long *wpms = (long *)calloc(dk_ndrive, sizeof(long)); + KREAD(NPTR(X_DK_WPMS), wpms, dk_ndrive * sizeof (long)); + for (i = 0; i < dk_ndrive; i++) + *(dk_mspw + i) = (*(wpms + i) == 0)? 0.0: + (float) 1.0 / *(wpms + i); + free(wpms); + } + dr_name = (char **)calloc(dk_ndrive, sizeof (char *)); + dk_select = (int *)calloc(dk_ndrive, sizeof (int)); + for (cp = buf, i = 0; i < dk_ndrive; i++) { + dr_name[i] = cp; + sprintf(dr_name[i], "dk%d", i); + cp += strlen(dr_name[i]) + 1; + if (dk_mspw[i] != 0.0) + dk_select[i] = 1; + } + if (!read_names()) { + free(dr_name); + free(dk_select); + free(dk_mspw); + return(0); + } + once = 1; + return(1); +} + +int +dkcmd(cmd, args) + char *cmd, *args; +{ + if (prefix(cmd, "display") || prefix(cmd, "add")) { + dkselect(args, 1, dk_select); + return (1); + } + if (prefix(cmd, "ignore") || prefix(cmd, "delete")) { + dkselect(args, 0, dk_select); + return (1); + } + if (prefix(cmd, "drives")) { + register int i; + + move(CMDLINE, 0); clrtoeol(); + for (i = 0; i < dk_ndrive; i++) + if (dk_mspw[i] != 0.0) + printw("%s ", dr_name[i]); + return (1); + } + return (0); +} + +static void +dkselect(args, truefalse, selections) + char *args; + int truefalse, selections[]; +{ + register char *cp; + register int i; + char *index(); + + cp = index(args, '\n'); + if (cp) + *cp = '\0'; + for (;;) { + for (cp = args; *cp && isspace(*cp); cp++) + ; + args = cp; + for (; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (cp - args == 0) + break; + for (i = 0; i < dk_ndrive; i++) + if (strcmp(args, dr_name[i]) == 0) { + if (dk_mspw[i] != 0.0) + selections[i] = truefalse; + else + error("%s: drive not configured", + dr_name[i]); + break; + } + if (i >= dk_ndrive) + error("%s: unknown drive", args); + args = cp; + } +} diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h new file mode 100644 index 0000000..673278b --- /dev/null +++ b/usr.bin/systat/extern.h @@ -0,0 +1,118 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +#include +#include +#include + +extern struct cmdtab *curcmd; +extern struct cmdtab cmdtab[]; +extern struct text *xtext; +extern WINDOW *wnd; +extern char **dr_name; +extern char c, *namp, hostname[]; +extern double avenrun[3]; +extern float *dk_mspw; +extern kvm_t *kd; +extern long ntext, textp; +extern int *dk_select; +extern int CMDLINE; +extern int dk_ndrive; +extern int hz, stathz; +extern int naptime, col; +extern int nhosts; +extern int nports; +extern int protos; +extern int verbose; + +struct inpcb; + +int checkhost __P((struct inpcb *)); +int checkport __P((struct inpcb *)); +void closeiostat __P((WINDOW *)); +void closekre __P((WINDOW *)); +void closembufs __P((WINDOW *)); +void closenetstat __P((WINDOW *)); +void closepigs __P((WINDOW *)); +void closeswap __P((WINDOW *)); +int cmdiostat __P((char *, char *)); +int cmdkre __P((char *, char *)); +int cmdnetstat __P((char *, char *)); +struct cmdtab *lookup __P((char *)); +void command __P((char *)); +void die __P((int)); +void display __P((int)); +int dkinit __P((void)); +int dkcmd __P((char *, char *)); +void error __P((const char *fmt, ...)); +void fetchiostat __P((void)); +void fetchkre __P((void)); +void fetchmbufs __P((void)); +void fetchnetstat __P((void)); +void fetchpigs __P((void)); +void fetchswap __P((void)); +int initiostat __P((void)); +int initkre __P((void)); +int initmbufs __P((void)); +int initnetstat __P((void)); +int initpigs __P((void)); +int initswap __P((void)); +int keyboard __P((void)); +int kvm_ckread __P((void *, void *, int)); +void labeliostat __P((void)); +void labelkre __P((void)); +void labelmbufs __P((void)); +void labelnetstat __P((void)); +void labelpigs __P((void)); +void labels __P((void)); +void labelswap __P((void)); +void load __P((void)); +int netcmd __P((char *, char *)); +void nlisterr __P((struct nlist [])); +WINDOW *openiostat __P((void)); +WINDOW *openkre __P((void)); +WINDOW *openmbufs __P((void)); +WINDOW *opennetstat __P((void)); +WINDOW *openpigs __P((void)); +WINDOW *openswap __P((void)); +int prefix __P((char *, char *)); +void showiostat __P((void)); +void showkre __P((void)); +void showmbufs __P((void)); +void shownetstat __P((void)); +void showpigs __P((void)); +void showswap __P((void)); +void status __P((void)); +void suspend __P((int)); diff --git a/usr.bin/systat/fetch.c b/usr.bin/systat/fetch.c new file mode 100644 index 0000000..49b296c --- /dev/null +++ b/usr.bin/systat/fetch.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)fetch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include "systat.h" +#include "extern.h" + +int +kvm_ckread(a, b, l) + void *a, *b; + int l; +{ + if (kvm_read(kd, (u_long)a, b, l) != l) { + if (verbose) + error("error reading kmem at %x\n", a); + return (0); + } + else + return (1); +} diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c new file mode 100644 index 0000000..b5412a5 --- /dev/null +++ b/usr.bin/systat/iostat.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1980, 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[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; +#endif not lint + +#include +#include +#include + +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static struct nlist namelist[] = { +#define X_DK_BUSY 0 + { "_dk_busy" }, +#define X_DK_TIME 1 + { "_dk_time" }, +#define X_DK_XFER 2 + { "_dk_xfer" }, +#define X_DK_WDS 3 + { "_dk_wds" }, +#define X_DK_SEEK 4 + { "_dk_seek" }, +#define X_CP_TIME 5 + { "_cp_time" }, +#ifdef vax +#define X_MBDINIT (X_CP_TIME+1) + { "_mbdinit" }, +#define X_UBDINIT (X_CP_TIME+2) + { "_ubdinit" }, +#endif +#ifdef tahoe +#define X_VBDINIT (X_CP_TIME+1) + { "_vbdinit" }, +#endif + { "" }, +}; + +static struct { + int dk_busy; + long cp_time[CPUSTATES]; + long *dk_time; + long *dk_wds; + long *dk_seek; + long *dk_xfer; +} s, s1; + +static int linesperregion; +static double etime; +static int numbers = 0; /* default display bar graphs */ +static int msps = 0; /* default ms/seek shown */ + +static int barlabels __P((int)); +static void histogram __P((double, int, double)); +static int numlabels __P((int)); +static int stats __P((int, int, int)); +static void stat1 __P((int, int)); + + +WINDOW * +openiostat() +{ + return (subwin(stdscr, LINES-1-5, 0, 5, 0)); +} + +void +closeiostat(w) + WINDOW *w; +{ + if (w == NULL) + return; + wclear(w); + wrefresh(w); + delwin(w); +} + +int +initiostat() +{ + if (namelist[X_DK_BUSY].n_type == 0) { + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[X_DK_BUSY].n_type == 0) { + error("Disk init information isn't in namelist"); + return(0); + } + } + if (! dkinit()) + return(0); + if (dk_ndrive) { +#define allocate(e, t) \ + s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ + s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); + allocate(dk_time, long); + allocate(dk_wds, long); + allocate(dk_seek, long); + allocate(dk_xfer, long); +#undef allocate + } + return(1); +} + +void +fetchiostat() +{ + if (namelist[X_DK_BUSY].n_type == 0) + return; + NREAD(X_DK_BUSY, &s.dk_busy, LONG); + NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG); + NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG); + NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG); + NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG); + NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time); +} + +#define INSET 10 + +void +labeliostat() +{ + int row; + + if (namelist[X_DK_BUSY].n_type == 0) { + error("No dk_busy defined."); + return; + } + row = 0; + wmove(wnd, row, 0); wclrtobot(wnd); + mvwaddstr(wnd, row++, INSET, + "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); + mvwaddstr(wnd, row++, 0, "cpu user|"); + mvwaddstr(wnd, row++, 0, " nice|"); + mvwaddstr(wnd, row++, 0, " system|"); + mvwaddstr(wnd, row++, 0, " idle|"); + if (numbers) + row = numlabels(row + 1); + else + row = barlabels(row + 1); +} + +static int +numlabels(row) + int row; +{ + int i, col, regions, ndrives; + +#define COLWIDTH 14 +#define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH) + for (ndrives = 0, i = 0; i < dk_ndrive; i++) + if (dk_select[i]) + ndrives++; + regions = howmany(ndrives, DRIVESPERLINE); + /* + * Deduct -regions for blank line after each scrolling region. + */ + linesperregion = (wnd->maxy - row - regions) / regions; + /* + * Minimum region contains space for two + * label lines and one line of statistics. + */ + if (linesperregion < 3) + linesperregion = 3; + col = 0; + for (i = 0; i < dk_ndrive; i++) + if (dk_select[i] && dk_mspw[i] != 0.0) { + if (col + COLWIDTH >= wnd->maxx - INSET) { + col = 0, row += linesperregion + 1; + if (row > wnd->maxy - (linesperregion + 1)) + break; + } + mvwaddstr(wnd, row, col + 4, dr_name[i]); + mvwaddstr(wnd, row + 1, col, "bps tps msps"); + col += COLWIDTH; + } + if (col) + row += linesperregion + 1; + return (row); +} + +static int +barlabels(row) + int row; +{ + int i; + + mvwaddstr(wnd, row++, INSET, + "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50"); + linesperregion = 2 + msps; + for (i = 0; i < dk_ndrive; i++) + if (dk_select[i] && dk_mspw[i] != 0.0) { + if (row > wnd->maxy - linesperregion) + break; + mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]); + mvwaddstr(wnd, row++, 0, " tps|"); + if (msps) + mvwaddstr(wnd, row++, 0, " msps|"); + } + return (row); +} + + +void +showiostat() +{ + register long t; + register int i, row, col; + + if (namelist[X_DK_BUSY].n_type == 0) + return; + for (i = 0; i < dk_ndrive; i++) { +#define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t + X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); + } + etime = 0; + for(i = 0; i < CPUSTATES; i++) { + X(cp_time); + etime += s.cp_time[i]; + } + if (etime == 0.0) + etime = 1.0; + etime /= (float) hz; + row = 1; + + /* + * Last CPU state not calculated yet. + */ + for (i = 0; i < CPUSTATES - 1; i++) + stat1(row++, i); + if (!numbers) { + row += 2; + for (i = 0; i < dk_ndrive; i++) + if (dk_select[i] && dk_mspw[i] != 0.0) { + if (row > wnd->maxy - linesperregion) + break; + row = stats(row, INSET, i); + } + return; + } + col = 0; + wmove(wnd, row + linesperregion, 0); + wdeleteln(wnd); + wmove(wnd, row + 3, 0); + winsertln(wnd); + for (i = 0; i < dk_ndrive; i++) + if (dk_select[i] && dk_mspw[i] != 0.0) { + if (col + COLWIDTH >= wnd->maxx) { + col = 0, row += linesperregion + 1; + if (row > wnd->maxy - (linesperregion + 1)) + break; + wmove(wnd, row + linesperregion, 0); + wdeleteln(wnd); + wmove(wnd, row + 3, 0); + winsertln(wnd); + } + (void) stats(row + 3, col, i); + col += COLWIDTH; + } +} + +static int +stats(row, col, dn) + int row, col, dn; +{ + double atime, words, xtime, itime; + + atime = s.dk_time[dn]; + atime /= (float) hz; + words = s.dk_wds[dn]*32.0; /* number of words transferred */ + xtime = dk_mspw[dn]*words; /* transfer time */ + itime = atime - xtime; /* time not transferring */ + if (xtime < 0) + itime += xtime, xtime = 0; + if (itime < 0) + xtime += itime, itime = 0; + if (numbers) { + mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f", + words / 512 / etime, s.dk_xfer[dn] / etime, + s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0); + return (row); + } + wmove(wnd, row++, col); + histogram(words / 512 / etime, 50, 1.0); + wmove(wnd, row++, col); + histogram(s.dk_xfer[dn] / etime, 50, 1.0); + if (msps) { + wmove(wnd, row++, col); + histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0, + 50, 1.0); + } + return (row); +} + +static void +stat1(row, o) + int row, o; +{ + register int i; + double time; + + time = 0; + for (i = 0; i < CPUSTATES; i++) + time += s.cp_time[i]; + if (time == 0.0) + time = 1.0; + wmove(wnd, row, INSET); +#define CPUSCALE 0.5 + histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE); +} + +static void +histogram(val, colwidth, scale) + double val; + int colwidth; + double scale; +{ + char buf[10]; + register int k; + register int v = (int)(val * scale) + 0.5; + + k = MIN(v, colwidth); + if (v > colwidth) { + sprintf(buf, "%4.1f", val); + k -= strlen(buf); + while (k--) + waddch(wnd, 'X'); + waddstr(wnd, buf); + return; + } + while (k--) + waddch(wnd, 'X'); + wclrtoeol(wnd); +} + +int +cmdiostat(cmd, args) + char *cmd, *args; +{ + + if (prefix(cmd, "msps")) + msps = !msps; + else if (prefix(cmd, "numbers")) + numbers = 1; + else if (prefix(cmd, "bars")) + numbers = 0; + else if (!dkcmd(cmd, args)) + return (0); + wclear(wnd); + labeliostat(); + refresh(); + return (1); +} diff --git a/usr.bin/systat/keyboard.c b/usr.bin/systat/keyboard.c new file mode 100644 index 0000000..ae4feb5 --- /dev/null +++ b/usr.bin/systat/keyboard.c @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)keyboard.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include "systat.h" +#include "extern.h" + +int +keyboard() +{ + char ch, line[80]; + int oldmask; + + for (;;) { + col = 0; + move(CMDLINE, 0); + do { + refresh(); + ch = getch() & 0177; + if (ch == 0177 && ferror(stdin)) { + clearerr(stdin); + continue; + } + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + if (col == 0) { +#define mask(s) (1 << ((s) - 1)) + if (ch == CTRL('l')) { + oldmask = sigblock(mask(SIGALRM)); + wrefresh(curscr); + sigsetmask(oldmask); + continue; + } + if (ch == CTRL('g')) { + oldmask = sigblock(mask(SIGALRM)); + status(); + sigsetmask(oldmask); + continue; + } + if (ch != ':') + continue; + move(CMDLINE, 0); + clrtoeol(); + } + if (ch == erasechar() && col > 0) { + if (col == 1 && line[0] == ':') + continue; + col--; + goto doerase; + } + if (ch == CTRL('w') && col > 0) { + while (--col >= 0 && isspace(line[col])) + ; + col++; + while (--col >= 0 && !isspace(line[col])) + if (col == 0 && line[0] == ':') + break; + col++; + goto doerase; + } + if (ch == killchar() && col > 0) { + col = 0; + if (line[0] == ':') + col++; + doerase: + move(CMDLINE, col); + clrtoeol(); + continue; + } + if (isprint(ch) || ch == ' ') { + line[col] = ch; + mvaddch(CMDLINE, col, ch); + col++; + } + } while (col == 0 || (ch != '\r' && ch != '\n')); + line[col] = '\0'; + oldmask = sigblock(mask(SIGALRM)); + command(line + 1); + sigsetmask(oldmask); + } + /*NOTREACHED*/ +} diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c new file mode 100644 index 0000000..f9f7672 --- /dev/null +++ b/usr.bin/systat/main.c @@ -0,0 +1,286 @@ +/*- + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static struct nlist namelist[] = { +#define X_FIRST 0 +#define X_HZ 0 + { "_hz" }, +#define X_STATHZ 1 + { "_stathz" }, + { "" } +}; +static int dellave; + +kvm_t *kd; +sig_t sigtstpdfl; +double avenrun[3]; +int col; +int naptime = 5; +int verbose = 1; /* to report kvm read errs */ +int hz, stathz; +char c; +char *namp; +char hostname[MAXHOSTNAMELEN]; +WINDOW *wnd; +int CMDLINE; + +static WINDOW *wload; /* one line window for load average */ + +void +main(argc, argv) + int argc; + char **argv; +{ + char errbuf[80]; + + argc--, argv++; + while (argc > 0) { + if (argv[0][0] == '-') { + struct cmdtab *p; + + p = lookup(&argv[0][1]); + if (p == (struct cmdtab *)-1) { + fprintf(stderr, "%s: unknown request\n", + &argv[0][1]); + exit(1); + } + curcmd = p; + } else { + naptime = atoi(argv[0]); + if (naptime <= 0) + naptime = 5; + } + argc--, argv++; + } + kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); + if (kd == NULL) { + error("%s", errbuf); + exit(1); + } + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + exit(1); + } + if (namelist[X_FIRST].n_type == 0) { + fprintf(stderr, "couldn't read namelist.\n"); + exit(1); + } + signal(SIGINT, die); + signal(SIGQUIT, die); + signal(SIGTERM, die); + + /* + * Initialize display. Load average appears in a one line + * window of its own. Current command's display appears in + * an overlapping sub-window of stdscr configured by the display + * routines to minimize update work by curses. + */ + initscr(); + CMDLINE = LINES - 1; + wnd = (*curcmd->c_open)(); + if (wnd == NULL) { + fprintf(stderr, "Couldn't initialize display.\n"); + die(0); + } + wload = newwin(1, 0, 3, 20); + if (wload == NULL) { + fprintf(stderr, "Couldn't set up load average window.\n"); + die(0); + } + gethostname(hostname, sizeof (hostname)); + NREAD(X_HZ, &hz, LONG); + NREAD(X_STATHZ, &stathz, LONG); + (*curcmd->c_init)(); + curcmd->c_flags |= CF_INIT; + labels(); + + dellave = 0.0; + + signal(SIGALRM, display); + display(0); + noecho(); + crmode(); + keyboard(); + /*NOTREACHED*/ +} + +void +labels() +{ + if (curcmd->c_flags & CF_LOADAV) { + mvaddstr(2, 20, + "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10"); + mvaddstr(3, 5, "Load Average"); + } + (*curcmd->c_label)(); +#ifdef notdef + mvprintw(21, 25, "CPU usage on %s", hostname); +#endif + refresh(); +} + +void +display(signo) + int signo; +{ + register int i, j; + + /* Get the load average over the last minute. */ + (void) getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])); + (*curcmd->c_fetch)(); + if (curcmd->c_flags & CF_LOADAV) { + j = 5.0*avenrun[0] + 0.5; + dellave -= avenrun[0]; + if (dellave >= 0.0) + c = '<'; + else { + c = '>'; + dellave = -dellave; + } + if (dellave < 0.1) + c = '|'; + dellave = avenrun[0]; + wmove(wload, 0, 0); wclrtoeol(wload); + for (i = (j > 50) ? 50 : j; i > 0; i--) + waddch(wload, c); + if (j > 50) + wprintw(wload, " %4.1f", avenrun[0]); + } + (*curcmd->c_refresh)(); + if (curcmd->c_flags & CF_LOADAV) + wrefresh(wload); + wrefresh(wnd); + move(CMDLINE, col); + refresh(); + alarm(naptime); +} + +void +load() +{ + + (void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); + mvprintw(CMDLINE, 0, "%4.1f %4.1f %4.1f", + avenrun[0], avenrun[1], avenrun[2]); + clrtoeol(); +} + +void +die(signo) + int signo; +{ + move(CMDLINE, 0); + clrtoeol(); + refresh(); + endwin(); + exit(0); +} + +#if __STDC__ +#include +#else +#include +#endif + +#if __STDC__ +void +error(const char *fmt, ...) +#else +void +error(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + char buf[255]; + int oy, ox; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + if (wnd) { + getyx(stdscr, oy, ox); + (void) vsprintf(buf, fmt, ap); + clrtoeol(); + standout(); + mvaddstr(CMDLINE, 0, buf); + standend(); + move(oy, ox); + refresh(); + } else { + (void) vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } + va_end(ap); +} + +void +nlisterr(namelist) + struct nlist namelist[]; +{ + int i, n; + + n = 0; + clear(); + mvprintw(2, 10, "systat: nlist: can't find following symbols:"); + for (i = 0; + namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++) + if (namelist[i].n_value == 0) + mvprintw(2 + ++n, 10, "%s", namelist[i].n_name); + move(CMDLINE, 0); + clrtoeol(); + refresh(); + endwin(); + exit(1); +} diff --git a/usr.bin/systat/mbufs.c b/usr.bin/systat/mbufs.c new file mode 100644 index 0000000..4b5ca66 --- /dev/null +++ b/usr.bin/systat/mbufs.c @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)mbufs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static struct mbstat *mb; + +char *mtnames[] = { + "free", + "data", + "headers", + "sockets", + "pcbs", + "routes", + "hosts", + "arps", + "socknames", + "zombies", + "sockopts", + "frags", + "rights", + "ifaddrs", +}; + +#define NNAMES (sizeof (mtnames) / sizeof (mtnames[0])) + +WINDOW * +openmbufs() +{ + return (subwin(stdscr, LINES-5-1, 0, 5, 0)); +} + +void +closembufs(w) + WINDOW *w; +{ + if (w == NULL) + return; + wclear(w); + wrefresh(w); + delwin(w); +} + +void +labelmbufs() +{ + wmove(wnd, 0, 0); wclrtoeol(wnd); + mvwaddstr(wnd, 0, 10, + "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50 /55 /60"); +} + +void +showmbufs() +{ + register int i, j, max, index; + char buf[10]; + + if (mb == 0) + return; + for (j = 0; j < wnd->maxy; j++) { + max = 0, index = -1; + for (i = 0; i < wnd->maxy; i++) + if (mb->m_mtypes[i] > max) { + max = mb->m_mtypes[i]; + index = i; + } + if (max == 0) + break; + if (j > NNAMES) + mvwprintw(wnd, 1+j, 0, "%10d", index); + else + mvwprintw(wnd, 1+j, 0, "%-10.10s", mtnames[index]); + wmove(wnd, 1 + j, 10); + if (max > 60) { + sprintf(buf, " %d", max); + max = 60; + while (max--) + waddch(wnd, 'X'); + waddstr(wnd, buf); + } else { + while (max--) + waddch(wnd, 'X'); + wclrtoeol(wnd); + } + mb->m_mtypes[index] = 0; + } + wmove(wnd, 1+j, 0); wclrtobot(wnd); +} + +static struct nlist namelist[] = { +#define X_MBSTAT 0 + { "_mbstat" }, + { "" } +}; + +int +initmbufs() +{ + if (namelist[X_MBSTAT].n_type == 0) { + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[X_MBSTAT].n_type == 0) { + error("namelist on %s failed", _PATH_UNIX); + return(0); + } + } + if (mb == 0) + mb = (struct mbstat *)calloc(1, sizeof (*mb)); + return(1); +} + +void +fetchmbufs() +{ + if (namelist[X_MBSTAT].n_type == 0) + return; + NREAD(X_MBSTAT, mb, sizeof (*mb)); +} diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c new file mode 100644 index 0000000..3790c2a --- /dev/null +++ b/usr.bin/systat/netcmds.c @@ -0,0 +1,308 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Common network command support routines. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +#define streq(a,b) (strcmp(a,b)==0) + +static struct hitem { + struct in_addr addr; + int onoff; +} *hosts; + +int nports, nhosts, protos; + +static void changeitems __P((char *, int)); +static int selectproto __P((char *)); +static void showprotos __P((void)); +static int selectport __P((long, int)); +static void showports __P((void)); +static int selecthost __P((struct in_addr *, int)); +static void showhosts __P((void)); + +int +netcmd(cmd, args) + char *cmd, *args; +{ + + if (prefix(cmd, "tcp") || prefix(cmd, "udp")) { + selectproto(cmd); + return (1); + } + if (prefix(cmd, "ignore") || prefix(cmd, "display")) { + changeitems(args, prefix(cmd, "display")); + return (1); + } + if (prefix(cmd, "reset")) { + selectproto(0); + selecthost(0, 0); + selectport(-1, 0); + return (1); + } + if (prefix(cmd, "show")) { + move(CMDLINE, 0); clrtoeol(); + if (*args == '\0') { + showprotos(); + showhosts(); + showports(); + return (1); + } + if (prefix(args, "protos")) + showprotos(); + else if (prefix(args, "hosts")) + showhosts(); + else if (prefix(args, "ports")) + showports(); + else + addstr("show what?"); + return (1); + } + return (0); +} + + +static void +changeitems(args, onoff) + char *args; + int onoff; +{ + register char *cp; + struct servent *sp; + struct hostent *hp; + struct in_addr in; + char *index(); + + cp = index(args, '\n'); + if (cp) + *cp = '\0'; + for (;;args = cp) { + for (cp = args; *cp && isspace(*cp); cp++) + ; + args = cp; + for (; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (cp - args == 0) + break; + sp = getservbyname(args, + protos == TCP ? "tcp" : protos == UDP ? "udp" : 0); + if (sp) { + selectport(sp->s_port, onoff); + continue; + } + hp = gethostbyname(args); + if (hp == 0) { + in.s_addr = inet_addr(args); + if (in.s_addr == -1) { + error("%s: unknown host or port", args); + continue; + } + } else + in = *(struct in_addr *)hp->h_addr; + selecthost(&in, onoff); + } +} + +static int +selectproto(proto) + char *proto; +{ + int new = protos; + + if (proto == 0 || streq(proto, "all")) + new = TCP|UDP; + else if (streq(proto, "tcp")) + new = TCP; + else if (streq(proto, "udp")) + new = UDP; + return (new != protos, protos = new); +} + +static void +showprotos() +{ + + if ((protos&TCP) == 0) + addch('!'); + addstr("tcp "); + if ((protos&UDP) == 0) + addch('!'); + addstr("udp "); +} + +static struct pitem { + long port; + int onoff; +} *ports; + +static int +selectport(port, onoff) + long port; + int onoff; +{ + register struct pitem *p; + + if (port == -1) { + if (ports == 0) + return (0); + free((char *)ports), ports = 0; + nports = 0; + return (1); + } + for (p = ports; p < ports+nports; p++) + if (p->port == port) { + p->onoff = onoff; + return (0); + } + if (nports == 0) + ports = (struct pitem *)malloc(sizeof (*p)); + else + ports = (struct pitem *)realloc(ports, (nports+1)*sizeof (*p)); + p = &ports[nports++]; + p->port = port; + p->onoff = onoff; + return (1); +} + +int +checkport(inp) + register struct inpcb *inp; +{ + register struct pitem *p; + + if (ports) + for (p = ports; p < ports+nports; p++) + if (p->port == inp->inp_lport || p->port == inp->inp_fport) + return (p->onoff); + return (1); +} + +static void +showports() +{ + register struct pitem *p; + struct servent *sp; + + for (p = ports; p < ports+nports; p++) { + sp = getservbyport(p->port, + protos == TCP|UDP ? 0 : protos == TCP ? "tcp" : "udp"); + if (!p->onoff) + addch('!'); + if (sp) + printw("%s ", sp->s_name); + else + printw("%d ", p->port); + } +} + +static int +selecthost(in, onoff) + struct in_addr *in; + int onoff; +{ + register struct hitem *p; + + if (in == 0) { + if (hosts == 0) + return (0); + free((char *)hosts), hosts = 0; + nhosts = 0; + return (1); + } + for (p = hosts; p < hosts+nhosts; p++) + if (p->addr.s_addr == in->s_addr) { + p->onoff = onoff; + return (0); + } + if (nhosts == 0) + hosts = (struct hitem *)malloc(sizeof (*p)); + else + hosts = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p)); + p = &hosts[nhosts++]; + p->addr = *in; + p->onoff = onoff; + return (1); +} + +int +checkhost(inp) + register struct inpcb *inp; +{ + register struct hitem *p; + + if (hosts) + for (p = hosts; p < hosts+nhosts; p++) + if (p->addr.s_addr == inp->inp_laddr.s_addr || + p->addr.s_addr == inp->inp_faddr.s_addr) + return (p->onoff); + return (1); +} + +static void +showhosts() +{ + register struct hitem *p; + struct hostent *hp; + + for (p = hosts; p < hosts+nhosts; p++) { + hp = gethostbyaddr((char *)&p->addr, sizeof (p->addr), AF_INET); + if (!p->onoff) + addch('!'); + printw("%s ", hp ? hp->h_name : (char *)inet_ntoa(p->addr)); + } +} diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c new file mode 100644 index 0000000..0303bf5 --- /dev/null +++ b/usr.bin/systat/netstat.c @@ -0,0 +1,470 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * netstat + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TCPSTATES +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static void enter __P((struct inpcb *, struct socket *, int, char *)); +static char *inetname __P((struct in_addr)); +static void inetprint __P((struct in_addr *, int, char *)); + +#define streq(a,b) (strcmp(a,b)==0) +#define YMAX(w) ((w)->maxy-1) + +WINDOW * +opennetstat() +{ + sethostent(1); + setnetent(1); + return (subwin(stdscr, LINES-5-1, 0, 5, 0)); +} + +struct netinfo { + struct netinfo *ni_forw, *ni_prev; + short ni_line; /* line on screen */ + short ni_seen; /* 0 when not present in list */ + short ni_flags; +#define NIF_LACHG 0x1 /* local address changed */ +#define NIF_FACHG 0x2 /* foreign address changed */ + short ni_state; /* tcp state */ + char *ni_proto; /* protocol */ + struct in_addr ni_laddr; /* local address */ + long ni_lport; /* local port */ + struct in_addr ni_faddr; /* foreign address */ + long ni_fport; /* foreign port */ + long ni_rcvcc; /* rcv buffer character count */ + long ni_sndcc; /* snd buffer character count */ +}; + +static struct { + struct netinfo *ni_forw, *ni_prev; +} netcb; + +static int aflag = 0; +static int nflag = 0; +static int lastrow = 1; +static void enter(), inetprint(); +static char *inetname(); + +void +closenetstat(w) + WINDOW *w; +{ + register struct netinfo *p; + + endhostent(); + endnetent(); + p = (struct netinfo *)netcb.ni_forw; + while (p != (struct netinfo *)&netcb) { + if (p->ni_line != -1) + lastrow--; + p->ni_line = -1; + p = p->ni_forw; + } + if (w != NULL) { + wclear(w); + wrefresh(w); + delwin(w); + } +} + +static struct nlist namelist[] = { +#define X_TCB 0 + { "_tcb" }, +#define X_UDB 1 + { "_udb" }, + { "" }, +}; + +int +initnetstat() +{ + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[X_TCB].n_value == 0) { + error("No symbols in namelist"); + return(0); + } + netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb; + protos = TCP|UDP; + return(1); +} + +void +fetchnetstat() +{ + register struct inpcb *prev, *next; + register struct netinfo *p; + struct inpcb inpcb; + struct socket sockb; + struct tcpcb tcpcb; + void *off; + int istcp; + + if (namelist[X_TCB].n_value == 0) + return; + for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) + p->ni_seen = 0; + if (protos&TCP) { + off = NPTR(X_TCB); + istcp = 1; + } + else if (protos&UDP) { + off = NPTR(X_UDB); + istcp = 0; + } + else { + error("No protocols to display"); + return; + } +again: + KREAD(off, &inpcb, sizeof (struct inpcb)); + prev = off; + for (; inpcb.inp_next != off; prev = next) { + next = inpcb.inp_next; + KREAD(next, &inpcb, sizeof (inpcb)); + if (inpcb.inp_prev != prev) { + p = netcb.ni_forw; + for (; p != (struct netinfo *)&netcb; p = p->ni_forw) + p->ni_seen = 1; + error("Kernel state in transition"); + return; + } + if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) + continue; + if (nhosts && !checkhost(&inpcb)) + continue; + if (nports && !checkport(&inpcb)) + continue; + KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); + if (istcp) { + KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); + enter(&inpcb, &sockb, tcpcb.t_state, "tcp"); + } else + enter(&inpcb, &sockb, 0, "udp"); + } + if (istcp && (protos&UDP)) { + istcp = 0; + off = NPTR(X_UDB); + goto again; + } +} + +static void +enter(inp, so, state, proto) + register struct inpcb *inp; + register struct socket *so; + int state; + char *proto; +{ + register struct netinfo *p; + + /* + * Only take exact matches, any sockets with + * previously unbound addresses will be deleted + * below in the display routine because they + * will appear as ``not seen'' in the kernel + * data structures. + */ + for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { + if (!streq(proto, p->ni_proto)) + continue; + if (p->ni_lport != inp->inp_lport || + p->ni_laddr.s_addr != inp->inp_laddr.s_addr) + continue; + if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr && + p->ni_fport == inp->inp_fport) + break; + } + if (p == (struct netinfo *)&netcb) { + if ((p = malloc(sizeof(*p))) == NULL) { + error("Out of memory"); + return; + } + p->ni_prev = (struct netinfo *)&netcb; + p->ni_forw = netcb.ni_forw; + netcb.ni_forw->ni_prev = p; + netcb.ni_forw = p; + p->ni_line = -1; + p->ni_laddr = inp->inp_laddr; + p->ni_lport = inp->inp_lport; + p->ni_faddr = inp->inp_faddr; + p->ni_fport = inp->inp_fport; + p->ni_proto = proto; + p->ni_flags = NIF_LACHG|NIF_FACHG; + } + p->ni_rcvcc = so->so_rcv.sb_cc; + p->ni_sndcc = so->so_snd.sb_cc; + p->ni_state = state; + p->ni_seen = 1; +} + +/* column locations */ +#define LADDR 0 +#define FADDR LADDR+23 +#define PROTO FADDR+23 +#define RCVCC PROTO+6 +#define SNDCC RCVCC+7 +#define STATE SNDCC+7 + + +void +labelnetstat() +{ + if (namelist[X_TCB].n_type == 0) + return; + wmove(wnd, 0, 0); wclrtobot(wnd); + mvwaddstr(wnd, 0, LADDR, "Local Address"); + mvwaddstr(wnd, 0, FADDR, "Foreign Address"); + mvwaddstr(wnd, 0, PROTO, "Proto"); + mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); + mvwaddstr(wnd, 0, SNDCC, "Send-Q"); + mvwaddstr(wnd, 0, STATE, "(state)"); +} + +void +shownetstat() +{ + register struct netinfo *p, *q; + + /* + * First, delete any connections that have gone + * away and adjust the position of connections + * below to reflect the deleted line. + */ + p = netcb.ni_forw; + while (p != (struct netinfo *)&netcb) { + if (p->ni_line == -1 || p->ni_seen) { + p = p->ni_forw; + continue; + } + wmove(wnd, p->ni_line, 0); wdeleteln(wnd); + q = netcb.ni_forw; + for (; q != (struct netinfo *)&netcb; q = q->ni_forw) + if (q != p && q->ni_line > p->ni_line) { + q->ni_line--; + /* this shouldn't be necessary */ + q->ni_flags |= NIF_LACHG|NIF_FACHG; + } + lastrow--; + q = p->ni_forw; + p->ni_prev->ni_forw = p->ni_forw; + p->ni_forw->ni_prev = p->ni_prev; + free(p); + p = q; + } + /* + * Update existing connections and add new ones. + */ + for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { + if (p->ni_line == -1) { + /* + * Add a new entry if possible. + */ + if (lastrow > YMAX(wnd)) + continue; + p->ni_line = lastrow++; + p->ni_flags |= NIF_LACHG|NIF_FACHG; + } + if (p->ni_flags & NIF_LACHG) { + wmove(wnd, p->ni_line, LADDR); + inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto); + p->ni_flags &= ~NIF_LACHG; + } + if (p->ni_flags & NIF_FACHG) { + wmove(wnd, p->ni_line, FADDR); + inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto); + p->ni_flags &= ~NIF_FACHG; + } + mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto); + mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc); + mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc); + if (streq(p->ni_proto, "tcp")) + if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES) + mvwprintw(wnd, p->ni_line, STATE, "%d", + p->ni_state); + else + mvwaddstr(wnd, p->ni_line, STATE, + tcpstates[p->ni_state]); + wclrtoeol(wnd); + } + if (lastrow < YMAX(wnd)) { + wmove(wnd, lastrow, 0); wclrtobot(wnd); + wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd); /* XXX */ + } +} + +/* + * Pretty print an Internet address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ +static void +inetprint(in, port, proto) + register struct in_addr *in; + int port; + char *proto; +{ + struct servent *sp = 0; + char line[80], *cp, *index(); + + sprintf(line, "%.*s.", 16, inetname(*in)); + cp = index(line, '\0'); + if (!nflag && port) + sp = getservbyport(port, proto); + if (sp || port == 0) + sprintf(cp, "%.8s", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d", ntohs((u_short)port)); + /* pad to full column to clear any garbage */ + cp = index(line, '\0'); + while (cp - line < 22) + *cp++ = ' '; + *cp = '\0'; + waddstr(wnd, line); +} + +/* + * Construct an Internet address representation. + * If the nflag has been supplied, give + * numeric value, otherwise try for symbolic name. + */ +static char * +inetname(in) + struct in_addr in; +{ + char *cp = 0; + static char line[50]; + struct hostent *hp; + struct netent *np; + + if (!nflag && in.s_addr != INADDR_ANY) { + int net = inet_netof(in); + int lna = inet_lnaof(in); + + if (lna == INADDR_ANY) { + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp == 0) { + hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); + if (hp) + cp = hp->h_name; + } + } + if (in.s_addr == INADDR_ANY) + strcpy(line, "*"); + else if (cp) + strcpy(line, cp); + else { + in.s_addr = ntohl(in.s_addr); +#define C(x) ((x) & 0xff) + sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), + C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); + } + return (line); +} + +int +cmdnetstat(cmd, args) + char *cmd, *args; +{ + register struct netinfo *p; + + if (prefix(cmd, "all")) { + aflag = !aflag; + goto fixup; + } + if (prefix(cmd, "numbers") || prefix(cmd, "names")) { + int new; + + new = prefix(cmd, "numbers"); + if (new == nflag) + return (1); + p = netcb.ni_forw; + for (; p != (struct netinfo *)&netcb; p = p->ni_forw) { + if (p->ni_line == -1) + continue; + p->ni_flags |= NIF_LACHG|NIF_FACHG; + } + nflag = new; + goto redisplay; + } + if (!netcmd(cmd, args)) + return (0); +fixup: + fetchnetstat(); +redisplay: + shownetstat(); + refresh(); + return (1); +} diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c new file mode 100644 index 0000000..4c49494 --- /dev/null +++ b/usr.bin/systat/pigs.c @@ -0,0 +1,245 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)pigs.c 8.2 (Berkeley) 9/23/93"; +#endif /* not lint */ + +/* + * Pigs display from Bill Reeves at Lucasfilm + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "extern.h" +#include "systat.h" + +int compar __P((const void *, const void *)); + +static int nproc; +static struct p_times { + float pt_pctcpu; + struct kinfo_proc *pt_kp; +} *pt; + +static long stime[CPUSTATES]; +static int fscale; +static double lccpu; + +WINDOW * +openpigs() +{ + return (subwin(stdscr, LINES-5-1, 0, 5, 0)); +} + +void +closepigs(w) + WINDOW *w; +{ + if (w == NULL) + return; + wclear(w); + wrefresh(w); + delwin(w); +} + + +void +showpigs() +{ + register int i, j, y, k; + struct eproc *ep; + float total; + int factor; + char *uname, *pname, pidname[30]; + + if (pt == NULL) + return; + /* Accumulate the percent of cpu per user. */ + total = 0.0; + for (i = 0; i <= nproc; i++) { + /* Accumulate the percentage. */ + total += pt[i].pt_pctcpu; + } + + if (total < 1.0) + total = 1.0; + factor = 50.0/total; + + qsort(pt, nproc + 1, sizeof (struct p_times), compar); + y = 1; + i = nproc + 1; + if (i > wnd->maxy-1) + i = wnd->maxy-1; + for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) { + if (pt[k].pt_kp == NULL) { + uname = ""; + pname = ""; + } + else { + ep = &pt[k].pt_kp->kp_eproc; + uname = (char *)user_from_uid(ep->e_ucred.cr_uid, 0); + pname = pt[k].pt_kp->kp_proc.p_comm; + } + wmove(wnd, y, 0); + wclrtoeol(wnd); + mvwaddstr(wnd, y, 0, uname); + sprintf(pidname, "%10.10s", pname, 0); + mvwaddstr(wnd, y, 9, pidname); + wmove(wnd, y, 20); + for (j = pt[k].pt_pctcpu*factor + 0.5; j > 0; j--) + waddch(wnd, 'X'); + } + wmove(wnd, y, 0); wclrtobot(wnd); +} + +static struct nlist namelist[] = { +#define X_FIRST 0 +#define X_CPTIME 0 + { "_cp_time" }, +#define X_CCPU 1 + { "_ccpu" }, +#define X_FSCALE 2 + { "_fscale" }, + + { "" } +}; + +int +initpigs() +{ + fixpt_t ccpu; + + if (namelist[X_FIRST].n_type == 0) { + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[X_FIRST].n_type == 0) { + error("namelist failed"); + return(0); + } + } + KREAD(NPTR(X_CPTIME), stime, sizeof (stime)); + NREAD(X_CCPU, &ccpu, LONG); + NREAD(X_FSCALE, &fscale, LONG); + lccpu = log((double) ccpu / fscale); + + return(1); +} + +void +fetchpigs() +{ + register int i; + register float time; + register struct proc *pp; + register float *pctp; + struct kinfo_proc *kpp; + long ctime[CPUSTATES]; + double t; + static int lastnproc = 0; + + if (namelist[X_FIRST].n_type == 0) + return; + if ((kpp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)) == NULL) { + error("%s", kvm_geterr(kd)); + if (pt) + free(pt); + return; + } + if (nproc > lastnproc) { + free(pt); + if ((pt = + malloc((nproc + 1) * sizeof(struct p_times))) == NULL) { + error("Out of memory"); + die(0); + } + } + lastnproc = nproc; + /* + * calculate %cpu for each proc + */ + for (i = 0; i < nproc; i++) { + pt[i].pt_kp = &kpp[i]; + pp = &kpp[i].kp_proc; + pctp = &pt[i].pt_pctcpu; + time = pp->p_swtime; + if (time == 0 || (pp->p_flag & P_INMEM) == 0) + *pctp = 0; + else + *pctp = ((double) pp->p_pctcpu / + fscale) / (1.0 - exp(time * lccpu)); + } + /* + * and for the imaginary "idle" process + */ + KREAD(NPTR(X_CPTIME), ctime, sizeof (ctime)); + t = 0; + for (i = 0; i < CPUSTATES; i++) + t += ctime[i] - stime[i]; + if (t == 0.0) + t = 1.0; + pt[nproc].pt_kp = NULL; + pt[nproc].pt_pctcpu = (ctime[CP_IDLE] - stime[CP_IDLE]) / t; + for (i = 0; i < CPUSTATES; i++) + stime[i] = ctime[i]; +} + +void +labelpigs() +{ + wmove(wnd, 0, 0); + wclrtoeol(wnd); + mvwaddstr(wnd, 0, 20, + "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); +} + +int +compar(a, b) + const void *a, *b; +{ + return (((struct p_times *) a)->pt_pctcpu > + ((struct p_times *) b)->pt_pctcpu)? -1: 1; +} diff --git a/usr.bin/systat/swap.c b/usr.bin/systat/swap.c new file mode 100644 index 0000000..f587eb4 --- /dev/null +++ b/usr.bin/systat/swap.c @@ -0,0 +1,257 @@ +/*- + * Copyright (c) 1980, 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[] = "@(#)swap.c 8.2 (Berkeley) 2/21/94"; +#endif /* not lint */ + +/* + * swapinfo - based on a program of the same name by Kevin Lahey + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "systat.h" +#include "extern.h" + +extern char *devname __P((int, int)); +extern char *getbsize __P((int *headerlenp, long *blocksizep)); +void showspace __P((char *header, int hlen, long blocksize)); + +kvm_t *kd; + +struct nlist syms[] = { + { "_swapmap" }, /* list of free swap areas */ +#define VM_SWAPMAP 0 + { "_nswapmap" },/* size of the swap map */ +#define VM_NSWAPMAP 1 + { "_swdevt" }, /* list of swap devices and sizes */ +#define VM_SWDEVT 2 + { "_nswap" }, /* size of largest swap device */ +#define VM_NSWAP 3 + { "_nswdev" }, /* number of swap devices */ +#define VM_NSWDEV 4 + { "_dmmax" }, /* maximum size of a swap block */ +#define VM_DMMAX 5 + 0 +}; + +static int nswap, nswdev, dmmax, nswapmap; +static struct swdevt *sw; +static long *perdev, blocksize; +static struct map *swapmap, *kswapmap; +static struct mapent *mp; +static int nfree, hlen; + +#define SVAR(var) __STRING(var) /* to force expansion */ +#define KGET(idx, var) \ + KGET1(idx, &var, sizeof(var), SVAR(var)) +#define KGET1(idx, p, s, msg) \ + KGET2(syms[idx].n_value, p, s, msg) +#define KGET2(addr, p, s, msg) \ + if (kvm_read(kd, addr, p, s) != s) { \ + error("cannot read %s: %s", msg, kvm_geterr(kd)); \ + return (0); \ + } + +WINDOW * +openswap() +{ + return (subwin(stdscr, LINES-5-1, 0, 5, 0)); +} + +void +closeswap(w) + WINDOW *w; +{ + if (w == NULL) + return; + wclear(w); + wrefresh(w); + delwin(w); +} + +initswap() +{ + int i; + char msgbuf[BUFSIZ]; + static int once = 0; + + if (once) + return (1); + if (kvm_nlist(kd, syms)) { + strcpy(msgbuf, "systat: swap: cannot find"); + for (i = 0; syms[i].n_name != NULL; i++) { + if (syms[i].n_value == 0) { + strcat(msgbuf, " "); + strcat(msgbuf, syms[i].n_name); + } + } + error(msgbuf); + return (0); + } + KGET(VM_NSWAP, nswap); + KGET(VM_NSWDEV, nswdev); + KGET(VM_DMMAX, dmmax); + KGET(VM_NSWAPMAP, nswapmap); + KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */ + if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || + (perdev = malloc(nswdev * sizeof(*perdev))) == NULL || + (mp = malloc(nswapmap * sizeof(*mp))) == NULL) { + error("swap malloc"); + return (0); + } + KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt"); + once = 1; + return (1); +} + +void +fetchswap() +{ + int s, e, i; + + s = nswapmap * sizeof(*mp); + if (kvm_read(kd, (long)kswapmap, mp, s) != s) + error("cannot read swapmap: %s", kvm_geterr(kd)); + + /* first entry in map is `struct map'; rest are mapent's */ + swapmap = (struct map *)mp; + if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap) + error("panic: swap: nswapmap goof"); + + /* + * Count up swap space. + */ + nfree = 0; + bzero(perdev, nswdev * sizeof(*perdev)); + for (mp++; mp->m_addr != 0; mp++) { + s = mp->m_addr; /* start of swap region */ + e = mp->m_addr + mp->m_size; /* end of region */ + nfree += mp->m_size; + + /* + * Swap space is split up among the configured disks. + * The first dmmax blocks of swap space some from the + * first disk, the next dmmax blocks from the next, + * and so on. The list of free space joins adjacent + * free blocks, ignoring device boundries. If we want + * to keep track of this information per device, we'll + * just have to extract it ourselves. + */ + + /* calculate first device on which this falls */ + i = (s / dmmax) % nswdev; + while (s < e) { /* XXX this is inefficient */ + int bound = roundup(s + 1, dmmax); + + if (bound > e) + bound = e; + perdev[i] += bound - s; + if (++i >= nswdev) + i = 0; + s = bound; + } + } +} + +void +labelswap() +{ + char *header; + int row, i; + + row = 0; + wmove(wnd, row, 0); wclrtobot(wnd); + header = getbsize(&hlen, &blocksize); + mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s", + "Disk", hlen, header, "Used", + "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100%"); + for (i = 0; i < nswdev; i++) { + mvwprintw(wnd, i + 1, 0, "%-5s", + devname(sw[i].sw_dev, S_IFBLK)); + } +} + +void +showswap() +{ + int col, row, div, i, j, avail, npfree, used, xsize, xfree; + + div = blocksize / 512; + avail = npfree = 0; + for (i = 0; i < nswdev; i++) { + col = 5; + mvwprintw(wnd, i + 1, col, "%*d", hlen, sw[i].sw_nblks / div); + col += hlen; + /* + * Don't report statistics for partitions which have not + * yet been activated via swapon(8). + */ + if (!sw[i].sw_freed) { + mvwprintw(wnd, i + 1, col + 8, + "0 *** not available for swapping ***"); + continue; + } + xsize = sw[i].sw_nblks; + xfree = perdev[i]; + used = xsize - xfree; + mvwprintw(wnd, i + 1, col, "%9d ", used / div); + for (j = (100 * used / xsize + 1) / 2; j > 0; j--) + waddch(wnd, 'X'); + npfree++; + avail += xsize; + } + /* + * If only one partition has been set up via swapon(8), we don't + * need to bother with totals. + */ + if (npfree > 1) { + used = avail - nfree; + mvwprintw(wnd, i + 1, 0, "%-5s%*d%9d ", + "Total", hlen, avail / div, used / div); + for (j = (100 * used / avail + 1) / 2; j > 0; j--) + waddch(wnd, 'X'); + } +} diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 new file mode 100644 index 0000000..3b9a5d9 --- /dev/null +++ b/usr.bin/systat/systat.1 @@ -0,0 +1,423 @@ +.\" Copyright (c) 1985, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)systat.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt SYSTAT 1 +.Os BSD 4.3 +.Sh NAME +.Nm systat +.Nd display system statistics on a crt +.Sh SYNOPSIS +.Nm systat +.Op Fl display +.Op Ar refresh-interval +.Sh DESCRIPTION +.Nm Systat +displays various system statistics in a screen oriented fashion +using the curses screen display library, +.Xr curses 3 . +.Pp +While +.Nm systat +is running the screen is usually divided into two windows (an exception +is the vmstat display which uses the entire screen). The +upper window depicts the current system load average. The +information displayed in the lower window may vary, depending on +user commands. The last line on the screen is reserved for user +input and error messages. +.Pp +By default +.Nm systat +displays the processes getting the largest percentage of the processor +in the lower window. Other displays show swap space usage, disk +.Tn I/O +statistics (a la +.Xr iostat 1 ) , +virtual memory statistics (a la +.Xr vmstat 1 ) , +network ``mbuf'' utilization, and network connections (a la +.Xr netstat 1 ) . +.Pp +Input is interpreted at two different levels. +A ``global'' command interpreter processes all keyboard input. +If this command interpreter fails to recognize a command, the +input line is passed to a per-display command interpreter. This +allows each display to have certain display-specific commands. +.Pp +Command line options: +.Bl -tag -width "refresh_interval" +.It Fl Ns Ar display +The +.Fl +flag expects +.Ar display +to be one of: +.Ic pigs , +.Ic iostat , +.Ic swap , +.Ic mbufs , +.Ic vmstat +or +.Ic netstat . +These displays can also be requested interactively (without the +.Dq Fl ) +and are described in +full detail below. +.It Ar refresh-interval +The +.Ar refresh-value +specifies the screen refresh time interval in seconds. +.El +.Pp +Certain characters cause immediate action by +.Nm systat . +These are +.Bl -tag -width Fl +.It Ic \&^L +Refresh the screen. +.It Ic \&^G +Print the name of the current ``display'' being shown in +the lower window and the refresh interval. +.It Ic \&^Z +Stop +.Nm systat . +.It Ic \&: +Move the cursor to the command line and interpret the input +line typed as a command. While entering a command the +current character erase, word erase, and line kill characters +may be used. +.El +.Pp +The following commands are interpreted by the ``global'' +command interpreter. +.Bl -tag -width Fl +.It Ic help +Print the names of the available displays on the command line. +.It Ic load +Print the load average over the past 1, 5, and 15 minutes +on the command line. +.It Ic stop +Stop refreshing the screen. +.It Xo +.Op Ic start +.Op Ar number +.Xc +Start (continue) refreshing the screen. If a second, numeric, +argument is provided it is interpreted as a refresh interval +(in seconds). +Supplying only a number will set the refresh interval to this +value. +.It Ic quit +Exit +.Nm systat . +(This may be abbreviated to +.Ic q . ) +.El +.Pp +The available displays are: +.Bl -tag -width Ic +.It Ic pigs +Display, in the lower window, those processes resident in main +memory and getting the +largest portion of the processor (the default display). +When less than 100% of the +processor is scheduled to user processes, the remaining time +is accounted to the ``idle'' process. +.It Ic iostat +Display, in the lower window, statistics about processor use +and disk throughput. Statistics on processor use appear as +bar graphs of the amount of time executing in user mode (``user''), +in user mode running low priority processes (``nice''), in +system mode (``system''), and idle (``idle''). Statistics +on disk throughput show, for each drive, kilobytes of data transferred, +number of disk transactions performed, and average seek time +(in milliseconds). This information may be displayed as +bar graphs or as rows of numbers which scroll downward. Bar +graphs are shown by default; +.Pp +The following commands are specific to the +.Ic iostat +display; the minimum unambiguous prefix may be supplied. +.Pp +.Bl -tag -width Fl -compact +.It Cm numbers +Show the disk +.Tn I/O +statistics in numeric form. Values are +displayed in numeric columns which scroll downward. +.It Cm bars +Show the disk +.Tn I/O +statistics in bar graph form (default). +.It Cm msps +Toggle the display of average seek time (the default is to +not display seek times). +.El +.It Ic swap +Show information about swap space usage on all the +swap areas compiled into the kernel. +The first column is the device name of the partition. +The next column is the total space available in the partition. +The +.Ar Used +column indicates the total blocks used so far; +the graph shows the percentage of space in use on each partition. +If there are more than one swap partition in use, +a total line is also shown. +Areas known to the kernel, but not in use are shown as not available. +.It Ic mbufs +Display, in the lower window, the number of mbufs allocated +for particular uses, i.e. data, socket structures, etc. +.It Ic vmstat +Take over the entire display and show a (rather crowded) compendium +of statistics related to virtual memory usage, process scheduling, +device interrupts, system name translation cacheing, disk +.Tn I/O +etc. +.Pp +The upper left quadrant of the screen shows the number +of users logged in and the load average over the last one, five, +and fifteen minute intervals. +Below this line are statistics on memory utilization. +The first row of the table reports memory usage only among +active processes, that is processes that have run in the previous +twenty seconds. +The second row reports on memory usage of all processes. +The first column reports on the number of physical pages +claimed by processes. +The second column reports the number of physical pages that +are devoted to read only text pages. +The third and fourth columns report the same two figures for +virtual pages, that is the number of pages that would be +needed if all processes had all of their pages. +Finally the last column shows the number of physical pages +on the free list. +.Pp +Below the memory display is the disk usage display. +It reports the number of seeks, transfers, and number +of kilobyte blocks transferred per second averaged over the +refresh period of the display (by default, five seconds). +For some disks it also reports the average milliseconds per seek. +Note that the system only keeps statistics on at most four disks. +.Pp +Below the disk display is a list of the +average number of processes (over the last refresh interval) +that are runnable (`r'), in page wait (`p'), +in disk wait other than paging (`d'), +sleeping (`s'), and swapped out but desiring to run (`w'). +Below the queue length listing is a numerical listing and +a bar graph showing the amount of +system (shown as `='), user (shown as `>'), +nice (shown as `-'), and idle time (shown as ` '). +.Pp +At the bottom left are statistics on name translations. +It lists the number of names translated in the previous interval, +the number and percentage of the translations that were +handled by the system wide name translation cache, and +the number and percentage of the translations that were +handled by the per process name translation cache. +.Pp +Under the date in the upper right hand quadrant are statistics +on paging and swapping activity. +The first two columns report the average number of pages +brought in and out per second over the last refresh interval +due to page faults and the paging daemon. +The third and fourth columns report the average number of pages +brought in and out per second over the last refresh interval +due to swap requests initiated by the scheduler. +The first row of the display shows the average +number of disk transfers per second over the last refresh interval; +the second row of the display shows the average +number of pages transferred per second over the last refresh interval. +.Pp +Below the paging statistics is a line listing the average number of +total reclaims ('Rec'), +intransit blocking page faults (`It'), +swap text pages found in free list (`F/S'), +file system text pages found in free list (`F/F'), +reclaims from free list +pages freed by the clock daemon (`Fre'), +and sequential process pages freed (`SFr') +per second over the refresh interval. +.Pp +Below this line are statistics on the average number of +zero filled pages (`zf') and demand filled text pages (`xf') +per second over the refresh period. +The first row indicates the number of requests that were +resolved, the second row shows the number that were set up, +and the last row shows the percentage of setup requests that were +actually used. +Note that this percentage is usually less than 100%, +however it may exceed 100% if a large number of requests +are actually used long after they were set up during a +period when no new pages are being set up. +Thus this figure is most interesting when observed over +a long time period, such as from boot time +(see below on getting such a display). +.Pp +Below the page fill statistics is a column that +lists the average number of context switches (`Csw'), +traps (`Trp'; includes page faults), system calls (`Sys'), interrupts (`Int'), +characters output to DZ ports using +.No pseudo Ns -DMA +(`Pdm'), +network software interrupts (`Sof'), +page faults (`Flt'), pages scanned by the page daemon (`Scn'), +and revolutions of the page daemon's hand (`Rev') +per second over the refresh interval. +.Pp +Running down the right hand side of the display is a breakdown +of the interrupts being handled by the system. +At the top of the list is the total interrupts per second +over the time interval. +The rest of the column breaks down the total on a device +by device basis. +Only devices that have interrupted at least once since boot time are shown. +.Pp +The following commands are specific to the +.Ic vmstat +display; the minimum unambiguous prefix may be supplied. +.Pp +.Bl -tag -width Ar -compact +.It Cm boot +Display cumulative statistics since the system was booted. +.It Cm run +Display statistics as a running total from the point this +command is given. +.It Cm time +Display statistics averaged over the refresh interval (the default). +.It Cm zero +Reset running statistics to zero. +.El +.It Ic netstat +Display, in the lower window, network connections. By default, +network servers awaiting requests are not displayed. Each address +is displayed in the format ``host.port'', with each shown symbolically, +when possible. It is possible to have addresses displayed numerically, +limit the display to a set of ports, hosts, and/or protocols +(the minimum unambiguous prefix may be supplied): +.Pp +.Bl -tag -width Ar -compact +.It Cm all +Toggle the displaying of server processes awaiting requests (this +is the equivalent of the +.Fl a +flag to +.Ar netstat 1 ) . +.It Cm numbers +Display network addresses numerically. +.It Cm names +Display network addresses symbolically. +.It Ar protocol +Display only network connections using the indicated protocol +(currently either ``tcp'' or ``udp''). +.It Cm ignore Op Ar items +Do not display information about connections associated with +the specified hosts or ports. Hosts and ports may be specified +by name (``vangogh'', ``ftp''), or numerically. Host addresses +use the Internet dot notation (``128.32.0.9''). Multiple items +may be specified with a single command by separating them with +spaces. +.It Cm display Op Ar items +Display information about the connections associated with the +specified hosts or ports. As for +.Ar ignore , +.Op Ar items +may be names or numbers. +.It Cm show Op Ar ports\&|hosts +Show, on the command line, the currently selected protocols, +hosts, and ports. Hosts and ports which are being ignored +are prefixed with a `!'. If +.Ar ports +or +.Ar hosts +is supplied as an argument to +.Cm show , +then only the requested information will be displayed. +.It Cm reset +Reset the port, host, and protocol matching mechanisms to the default +(any protocol, port, or host). +.El +.El +.Pp +Commands to switch between displays may be abbreviated to the +minimum unambiguous prefix; for example, ``io'' for ``iostat''. +Certain information may be discarded when the screen size is +insufficient for display. For example, on a machine with 10 +drives the +.Ic iostat +bar graph displays only 3 drives on a 24 line terminal. When +a bar graph would overflow the allotted screen space it is +truncated and the actual value is printed ``over top'' of the bar. +.Pp +The following commands are common to each display which shows +information about disk drives. These commands are used to +select a set of drives to report on, should your system have +more drives configured than can normally be displayed on the +screen. +.Pp +.Bl -tag -width Tx -compact +.It Cm ignore Op Ar drives +Do not display information about the drives indicated. Multiple +drives may be specified, separated by spaces. +.It Cm display Op Ar drives +Display information about the drives indicated. Multiple drives +may be specified, separated by spaces. +.El +.Sh FILES +.Bl -tag -width /etc/networks -compact +.It Pa /vmunix +For the namelist. +.It Pa /dev/kmem +For information in main memory. +.It Pa /dev/drum +For information about swapped out processes. +.It Pa /etc/hosts +For host names. +.It Pa /etc/networks +For network names. +.It Pa /etc/services +For port names. +.El +.Sh HISTORY +The +.Nm systat +program appeared in +.Bx 4.3 . +.Sh BUGS +Takes 2-10 percent of the cpu. +Certain displays presume a minimum of 80 characters per line. +The +.Ic vmstat +display looks out of place because it is (it was added in as +a separate display rather than created as a new program). diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h new file mode 100644 index 0000000..72f65ff --- /dev/null +++ b/usr.bin/systat/systat.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1980, 1989, 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. + * + * @(#)systat.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +struct cmdtab { + char *c_name; /* command name */ + void (*c_refresh)(); /* display refresh */ + void (*c_fetch)(); /* sets up data structures */ + void (*c_label)(); /* label display */ + int (*c_init)(); /* initialize namelist, etc. */ + WINDOW *(*c_open)(); /* open display */ + void (*c_close)(); /* close display */ + int (*c_cmd)(); /* display command interpreter */ + char c_flags; /* see below */ +}; + +#define CF_INIT 0x1 /* been initialized */ +#define CF_LOADAV 0x2 /* display w/ load average */ + +#define TCP 0x1 +#define UDP 0x2 + +#define KREAD(addr, buf, len) kvm_ckread((addr), (buf), (len)) +#define NVAL(indx) namelist[(indx)].n_value +#define NPTR(indx) (void *)NVAL((indx)) +#define NREAD(indx, buf, len) kvm_ckread(NPTR((indx)), (buf), (len)) +#define LONG (sizeof (long)) diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c new file mode 100644 index 0000000..3558c50 --- /dev/null +++ b/usr.bin/systat/vmstat.c @@ -0,0 +1,687 @@ +/*- + * Copyright (c) 1983, 1989, 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[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94"; +#endif /* not lint */ + +/* + * Cursed vmstat -- from Robert Elz. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "systat.h" +#include "extern.h" + +static struct Info { + long time[CPUSTATES]; + struct vmmeter Cnt; + struct vmtotal Total; + long *dk_time; + long *dk_wds; + long *dk_seek; + long *dk_xfer; + int dk_busy; + struct nchstats nchstats; + long nchcount; + long *intrcnt; +} s, s1, s2, z; + +#define cnt s.Cnt +#define oldcnt s1.Cnt +#define total s.Total +#define nchtotal s.nchstats +#define oldnchtotal s1.nchstats + +static enum state { BOOT, TIME, RUN } state = TIME; + +static void allocinfo __P((struct Info *)); +static void copyinfo __P((struct Info *, struct Info *)); +static float cputime __P((int)); +static void dinfo __P((int, int)); +static void getinfo __P((struct Info *, enum state)); +static void putint __P((int, int, int, int)); +static void putfloat __P((double, int, int, int, int, int)); +static int ucount __P((void)); + +static int ut; +static char buf[26]; +static time_t t; +static double etime; +static float hertz; +static int nintr; +static long *intrloc; +static char **intrname; +static int nextintsrow; + +struct utmp utmp; + + +WINDOW * +openkre() +{ + + ut = open(_PATH_UTMP, O_RDONLY); + if (ut < 0) + error("No utmp"); + return (stdscr); +} + +void +closekre(w) + WINDOW *w; +{ + + (void) close(ut); + if (w == NULL) + return; + wclear(w); + wrefresh(w); +} + + +static struct nlist namelist[] = { +#define X_CPTIME 0 + { "_cp_time" }, +#define X_CNT 1 + { "_cnt" }, +#define X_TOTAL 2 + { "_total" }, +#define X_DK_BUSY 3 + { "_dk_busy" }, +#define X_DK_TIME 4 + { "_dk_time" }, +#define X_DK_XFER 5 + { "_dk_xfer" }, +#define X_DK_WDS 6 + { "_dk_wds" }, +#define X_DK_SEEK 7 + { "_dk_seek" }, +#define X_NCHSTATS 8 + { "_nchstats" }, +#define X_INTRNAMES 9 + { "_intrnames" }, +#define X_EINTRNAMES 10 + { "_eintrnames" }, +#define X_INTRCNT 11 + { "_intrcnt" }, +#define X_EINTRCNT 12 + { "_eintrcnt" }, + { "" }, +}; + +/* + * These constants define where the major pieces are laid out + */ +#define STATROW 0 /* uses 1 row and 68 cols */ +#define STATCOL 2 +#define MEMROW 2 /* uses 4 rows and 31 cols */ +#define MEMCOL 0 +#define PAGEROW 2 /* uses 4 rows and 26 cols */ +#define PAGECOL 36 +#define INTSROW 2 /* uses all rows to bottom and 17 cols */ +#define INTSCOL 63 +#define PROCSROW 7 /* uses 2 rows and 20 cols */ +#define PROCSCOL 0 +#define GENSTATROW 7 /* uses 2 rows and 30 cols */ +#define GENSTATCOL 20 +#define VMSTATROW 7 /* uses 17 rows and 12 cols */ +#define VMSTATCOL 48 +#define GRAPHROW 10 /* uses 3 rows and 51 cols */ +#define GRAPHCOL 0 +#define NAMEIROW 14 /* uses 3 rows and 38 cols */ +#define NAMEICOL 0 +#define DISKROW 18 /* uses 5 rows and 50 cols (for 9 drives) */ +#define DISKCOL 0 + +#define DRIVESPACE 9 /* max # for space */ + +#if DK_NDRIVE > DRIVESPACE +#define MAXDRIVES DRIVESPACE /* max # to display */ +#else +#define MAXDRIVES DK_NDRIVE /* max # to display */ +#endif + +int +initkre() +{ + char *intrnamebuf, *cp; + int i; + static int once = 0; + + if (namelist[0].n_type == 0) { + if (kvm_nlist(kd, namelist)) { + nlisterr(namelist); + return(0); + } + if (namelist[0].n_type == 0) { + error("No namelist"); + return(0); + } + } + hertz = stathz ? stathz : hz; + if (! dkinit()) + return(0); + if (dk_ndrive && !once) { +#define allocate(e, t) \ + s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ + s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ + s2./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ + z./**/e = (t *)calloc(dk_ndrive, sizeof (t)); + allocate(dk_time, long); + allocate(dk_wds, long); + allocate(dk_seek, long); + allocate(dk_xfer, long); + once = 1; +#undef allocate + } + if (nintr == 0) { + nintr = (namelist[X_EINTRCNT].n_value - + namelist[X_INTRCNT].n_value) / sizeof (long); + intrloc = calloc(nintr, sizeof (long)); + intrname = calloc(nintr, sizeof (long)); + intrnamebuf = malloc(namelist[X_EINTRNAMES].n_value - + namelist[X_INTRNAMES].n_value); + if (intrnamebuf == 0 || intrname == 0 || intrloc == 0) { + error("Out of memory\n"); + if (intrnamebuf) + free(intrnamebuf); + if (intrname) + free(intrname); + if (intrloc) + free(intrloc); + nintr = 0; + return(0); + } + NREAD(X_INTRNAMES, intrnamebuf, NVAL(X_EINTRNAMES) - + NVAL(X_INTRNAMES)); + for (cp = intrnamebuf, i = 0; i < nintr; i++) { + intrname[i] = cp; + cp += strlen(cp) + 1; + } + nextintsrow = INTSROW + 2; + allocinfo(&s); + allocinfo(&s1); + allocinfo(&s2); + allocinfo(&z); + } + getinfo(&s2, RUN); + copyinfo(&s2, &s1); + return(1); +} + +void +fetchkre() +{ + time_t now; + + time(&now); + strcpy(buf, ctime(&now)); + buf[16] = '\0'; + getinfo(&s, state); +} + +void +labelkre() +{ + register int i, j; + + clear(); + mvprintw(STATROW, STATCOL + 4, "users Load"); + mvprintw(MEMROW, MEMCOL, "Mem:KB REAL VIRTUAL"); + mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share"); + mvprintw(MEMROW + 2, MEMCOL, "Act"); + mvprintw(MEMROW + 3, MEMCOL, "All"); + + mvprintw(MEMROW + 1, MEMCOL + 31, "Free"); + + mvprintw(PAGEROW, PAGECOL, " PAGING SWAPPING "); + mvprintw(PAGEROW + 1, PAGECOL, " in out in out "); + mvprintw(PAGEROW + 2, PAGECOL, "count"); + mvprintw(PAGEROW + 3, PAGECOL, "pages"); + + mvprintw(INTSROW, INTSCOL + 3, " Interrupts"); + mvprintw(INTSROW + 1, INTSCOL + 9, "total"); + + mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "cow"); + mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "objlk"); + mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "objht"); + mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "zfod"); + mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "nzfod"); + mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "%%zfod"); + mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "kern"); + mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "wire"); + mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "act"); + mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "inact"); + mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "free"); + mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "daefr"); + mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "prcfr"); + mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "react"); + mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "scan"); + mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "hdrev"); + if (LINES - 1 > VMSTATROW + 16) + mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "intrn"); + + mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt"); + + mvprintw(GRAPHROW, GRAPHCOL, + " . %% Sys . %% User . %% Nice . %% Idle"); + mvprintw(PROCSROW, PROCSCOL, "Proc:r p d s w"); + mvprintw(GRAPHROW + 1, GRAPHCOL, + "| | | | | | | | | | |"); + + mvprintw(NAMEIROW, NAMEICOL, "Namei Sys-cache Proc-cache"); + mvprintw(NAMEIROW + 1, NAMEICOL, + " Calls hits %% hits %%"); + mvprintw(DISKROW, DISKCOL, "Discs"); + mvprintw(DISKROW + 1, DISKCOL, "seeks"); + mvprintw(DISKROW + 2, DISKCOL, "xfers"); + mvprintw(DISKROW + 3, DISKCOL, " blks"); + mvprintw(DISKROW + 4, DISKCOL, " msps"); + j = 0; + for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++) + if (dk_select[i]) { + mvprintw(DISKROW, DISKCOL + 5 + 5 * j, + " %3.3s", dr_name[j]); + j++; + } + for (i = 0; i < nintr; i++) { + if (intrloc[i] == 0) + continue; + mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", intrname[i]); + } +} + +#define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;} +#define Y(fld) {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;} +#define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \ + if(state == TIME) s1.nchstats.fld = t;} +#define PUTRATE(fld, l, c, w) \ + Y(fld); \ + putint((int)((float)s.fld/etime + 0.5), l, c, w) +#define MAXFAIL 5 + +static char cpuchar[CPUSTATES] = { '=' , '>', '-', ' ' }; +static char cpuorder[CPUSTATES] = { CP_SYS, CP_USER, CP_NICE, CP_IDLE }; + +void +showkre() +{ + float f1, f2; + int psiz, inttotal; + int i, l, c; + static int failcnt = 0; + + for (i = 0; i < dk_ndrive; i++) { + X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); + } + etime = 0; + for(i = 0; i < CPUSTATES; i++) { + X(time); + etime += s.time[i]; + } + if (etime < 5.0) { /* < 5 ticks - ignore this trash */ + if (failcnt++ >= MAXFAIL) { + clear(); + mvprintw(2, 10, "The alternate system clock has died!"); + mvprintw(3, 10, "Reverting to ``pigs'' display."); + move(CMDLINE, 0); + refresh(); + failcnt = 0; + sleep(5); + command("pigs"); + } + return; + } + failcnt = 0; + etime /= hertz; + inttotal = 0; + for (i = 0; i < nintr; i++) { + if (s.intrcnt[i] == 0) + continue; + if (intrloc[i] == 0) { + if (nextintsrow == LINES) + continue; + intrloc[i] = nextintsrow++; + mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", + intrname[i]); + } + X(intrcnt); + l = (int)((float)s.intrcnt[i]/etime + 0.5); + inttotal += l; + putint(l, intrloc[i], INTSCOL, 8); + } + putint(inttotal, INTSROW + 1, INTSCOL, 8); + Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss); + Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); + s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits + + nchtotal.ncs_miss + nchtotal.ncs_long; + if (state == TIME) + s1.nchcount = s.nchcount; + + psiz = 0; + f2 = 0.0; + + /* + * Last CPU state not calculated yet. + */ + for (c = 0; c < CPUSTATES - 1; c++) { + i = cpuorder[c]; + f1 = cputime(i); + f2 += f1; + l = (int) ((f2 + 1.0) / 2.0) - psiz; + if (c == 0) + putfloat(f1, GRAPHROW, GRAPHCOL + 1, 5, 1, 0); + else + putfloat(f1, GRAPHROW, GRAPHCOL + 12 * c, + 5, 1, 0); + move(GRAPHROW + 2, psiz); + psiz += l; + while (l-- > 0) + addch(cpuchar[c]); + } + + putint(ucount(), STATROW, STATCOL, 3); + putfloat(avenrun[0], STATROW, STATCOL + 17, 6, 2, 0); + putfloat(avenrun[1], STATROW, STATCOL + 23, 6, 2, 0); + putfloat(avenrun[2], STATROW, STATCOL + 29, 6, 2, 0); + mvaddstr(STATROW, STATCOL + 53, buf); +#define pgtokb(pg) ((pg) * cnt.v_page_size / 1024) + putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 3, 6); + putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 9, 6); + putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 15, 7); + putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 22, 7); + putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 3, 6); + putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 9, 6); + putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 15, 7); + putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 22, 7); + putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 29, 6); + putint(total.t_rq - 1, PROCSROW + 1, PROCSCOL + 3, 3); + putint(total.t_pw, PROCSROW + 1, PROCSCOL + 6, 3); + putint(total.t_dw, PROCSROW + 1, PROCSCOL + 9, 3); + putint(total.t_sl, PROCSROW + 1, PROCSCOL + 12, 3); + putint(total.t_sw, PROCSROW + 1, PROCSCOL + 15, 3); + PUTRATE(Cnt.v_cow_faults, VMSTATROW + 0, VMSTATCOL + 3, 6); + PUTRATE(Cnt.v_lookups, VMSTATROW + 1, VMSTATCOL + 3, 6); + PUTRATE(Cnt.v_hits, VMSTATROW + 2, VMSTATCOL + 3, 6); + PUTRATE(Cnt.v_zfod, VMSTATROW + 3, VMSTATCOL + 4, 5); + PUTRATE(Cnt.v_nzfod, VMSTATROW + 4, VMSTATCOL + 3, 6); + putfloat(cnt.v_nzfod == 0 ? 0.0 : (100.0 * cnt.v_zfod / cnt.v_nzfod), + VMSTATROW + 5, VMSTATCOL + 2, 7, 2, 1); + putint(pgtokb(cnt.v_kernel_pages), VMSTATROW + 6, VMSTATCOL, 9); + putint(pgtokb(cnt.v_wire_count), VMSTATROW + 7, VMSTATCOL, 9); + putint(pgtokb(cnt.v_active_count), VMSTATROW + 8, VMSTATCOL, 9); + putint(pgtokb(cnt.v_inactive_count), VMSTATROW + 9, VMSTATCOL, 9); + putint(pgtokb(cnt.v_free_count), VMSTATROW + 10, VMSTATCOL, 9); + PUTRATE(Cnt.v_dfree, VMSTATROW + 11, VMSTATCOL, 9); + PUTRATE(Cnt.v_pfree, VMSTATROW + 12, VMSTATCOL, 9); + PUTRATE(Cnt.v_reactivated, VMSTATROW + 13, VMSTATCOL, 9); + PUTRATE(Cnt.v_scan, VMSTATROW + 14, VMSTATCOL, 9); + PUTRATE(Cnt.v_rev, VMSTATROW + 15, VMSTATCOL, 9); + if (LINES - 1 > VMSTATROW + 16) + PUTRATE(Cnt.v_intrans, VMSTATROW + 16, VMSTATCOL, 9); + PUTRATE(Cnt.v_pageins, PAGEROW + 2, PAGECOL + 5, 5); + PUTRATE(Cnt.v_pageouts, PAGEROW + 2, PAGECOL + 10, 5); + PUTRATE(Cnt.v_swpin, PAGEROW + 2, PAGECOL + 15, 5); /* - */ + PUTRATE(Cnt.v_swpout, PAGEROW + 2, PAGECOL + 20, 5); /* - */ + PUTRATE(Cnt.v_pgpgin, PAGEROW + 3, PAGECOL + 5, 5); /* ? */ + PUTRATE(Cnt.v_pgpgout, PAGEROW + 3, PAGECOL + 10, 5); /* ? */ + PUTRATE(Cnt.v_pswpin, PAGEROW + 3, PAGECOL + 15, 5); /* - */ + PUTRATE(Cnt.v_pswpout, PAGEROW + 3, PAGECOL + 20, 5); /* - */ + PUTRATE(Cnt.v_swtch, GENSTATROW + 1, GENSTATCOL, 5); + PUTRATE(Cnt.v_trap, GENSTATROW + 1, GENSTATCOL + 5, 5); + PUTRATE(Cnt.v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 5); + PUTRATE(Cnt.v_intr, GENSTATROW + 1, GENSTATCOL + 15, 5); + PUTRATE(Cnt.v_soft, GENSTATROW + 1, GENSTATCOL + 20, 5); + PUTRATE(Cnt.v_faults, GENSTATROW + 1, GENSTATCOL + 25, 5); + mvprintw(DISKROW, DISKCOL + 5, " "); + for (i = 0, c = 0; i < dk_ndrive && c < MAXDRIVES; i++) + if (dk_select[i]) { + mvprintw(DISKROW, DISKCOL + 5 + 5 * c, + " %3.3s", dr_name[i]); + dinfo(i, ++c); + } + putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9); + putint(nchtotal.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 9, 9); +#define nz(x) ((x) ? (x) : 1) + putfloat(nchtotal.ncs_goodhits * 100.0 / nz(s.nchcount), + NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1); + putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 23, 9); + putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount), + NAMEIROW + 2, NAMEICOL + 34, 4, 0, 1); +#undef nz +} + +int +cmdkre(cmd, args) + char *cmd, *args; +{ + + if (prefix(cmd, "run")) { + copyinfo(&s2, &s1); + state = RUN; + return (1); + } + if (prefix(cmd, "boot")) { + state = BOOT; + copyinfo(&z, &s1); + return (1); + } + if (prefix(cmd, "time")) { + state = TIME; + return (1); + } + if (prefix(cmd, "zero")) { + if (state == RUN) + getinfo(&s1, RUN); + return (1); + } + return (dkcmd(cmd, args)); +} + +/* calculate number of users on the system */ +static int +ucount() +{ + register int nusers = 0; + + if (ut < 0) + return (0); + while (read(ut, &utmp, sizeof(utmp))) + if (utmp.ut_name[0] != '\0') + nusers++; + + lseek(ut, 0L, L_SET); + return (nusers); +} + +static float +cputime(indx) + int indx; +{ + double t; + register int i; + + t = 0; + for (i = 0; i < CPUSTATES; i++) + t += s.time[i]; + if (t == 0.0) + t = 1.0; + return (s.time[indx] * 100.0 / t); +} + +static void +putint(n, l, c, w) + int n, l, c, w; +{ + char b[128]; + + move(l, c); + if (n == 0) { + while (w-- > 0) + addch(' '); + return; + } + sprintf(b, "%*d", w, n); + if (strlen(b) > w) { + while (w-- > 0) + addch('*'); + return; + } + addstr(b); +} + +static void +putfloat(f, l, c, w, d, nz) + double f; + int l, c, w, d, nz; +{ + char b[128]; + + move(l, c); + if (nz && f == 0.0) { + while (--w >= 0) + addch(' '); + return; + } + sprintf(b, "%*.*f", w, d, f); + if (strlen(b) > w) { + while (--w >= 0) + addch('*'); + return; + } + addstr(b); +} + +static void +getinfo(s, st) + struct Info *s; + enum state st; +{ + int mib[2], size; + extern int errno; + + NREAD(X_CPTIME, s->time, sizeof s->time); + NREAD(X_CNT, &s->Cnt, sizeof s->Cnt); + NREAD(X_DK_BUSY, &s->dk_busy, LONG); + NREAD(X_DK_TIME, s->dk_time, dk_ndrive * LONG); + NREAD(X_DK_XFER, s->dk_xfer, dk_ndrive * LONG); + NREAD(X_DK_WDS, s->dk_wds, dk_ndrive * LONG); + NREAD(X_DK_SEEK, s->dk_seek, dk_ndrive * LONG); + NREAD(X_NCHSTATS, &s->nchstats, sizeof s->nchstats); + NREAD(X_INTRCNT, s->intrcnt, nintr * LONG); + size = sizeof(s->Total); + mib[0] = CTL_VM; + mib[1] = VM_METER; + if (sysctl(mib, 2, &s->Total, &size, NULL, 0) < 0) { + error("Can't get kernel info: %s\n", strerror(errno)); + bzero(&s->Total, sizeof(s->Total)); + } +} + +static void +allocinfo(s) + struct Info *s; +{ + + s->intrcnt = (long *) malloc(nintr * sizeof(long)); + if (s->intrcnt == NULL) { + fprintf(stderr, "systat: out of memory\n"); + exit(2); + } +} + +static void +copyinfo(from, to) + register struct Info *from, *to; +{ + long *time, *wds, *seek, *xfer; + long *intrcnt; + + /* + * time, wds, seek, and xfer are malloc'd so we have to + * save the pointers before the structure copy and then + * copy by hand. + */ + time = to->dk_time; wds = to->dk_wds; seek = to->dk_seek; + xfer = to->dk_xfer; intrcnt = to->intrcnt; + *to = *from; + bcopy(from->dk_time, to->dk_time = time, dk_ndrive * sizeof (long)); + bcopy(from->dk_wds, to->dk_wds = wds, dk_ndrive * sizeof (long)); + bcopy(from->dk_seek, to->dk_seek = seek, dk_ndrive * sizeof (long)); + bcopy(from->dk_xfer, to->dk_xfer = xfer, dk_ndrive * sizeof (long)); + bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int)); +} + +static void +dinfo(dn, c) + int dn, c; +{ + double words, atime, itime, xtime; + + c = DISKCOL + c * 5; + atime = s.dk_time[dn]; + atime /= hertz; + words = s.dk_wds[dn]*32.0; /* number of words transferred */ + xtime = dk_mspw[dn]*words; /* transfer time */ + itime = atime - xtime; /* time not transferring */ + if (xtime < 0) + itime += xtime, xtime = 0; + if (itime < 0) + xtime += itime, itime = 0; + putint((int)((float)s.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5); + putint((int)((float)s.dk_xfer[dn]/etime+0.5), DISKROW + 2, c, 5); + putint((int)(words/etime/512.0 + 0.5), DISKROW + 3, c, 5); + if (s.dk_seek[dn]) + putfloat(itime*1000.0/s.dk_seek[dn], DISKROW + 4, c, 5, 1, 1); + else + putint(0, DISKROW + 4, c, 5); +} diff --git a/usr.bin/tail/Makefile b/usr.bin/tail/Makefile new file mode 100644 index 0000000..de1c3c9 --- /dev/null +++ b/usr.bin/tail/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tail +SRCS= forward.c misc.c read.c reverse.c tail.c + +.include diff --git a/usr.bin/tail/extern.h b/usr.bin/tail/extern.h new file mode 100644 index 0000000..65efc14 --- /dev/null +++ b/usr.bin/tail/extern.h @@ -0,0 +1,53 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +#define WR(p, size) \ + if (write(STDOUT_FILENO, p, size) != size) \ + oerr(); + +enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE }; + +void forward __P((FILE *, enum STYLE, long, struct stat *)); +void reverse __P((FILE *, enum STYLE, long, struct stat *)); + +void bytes __P((FILE *, off_t)); +void lines __P((FILE *, off_t)); + +void err __P((int fatal, const char *fmt, ...)); +void ierr __P((void)); +void oerr __P((void)); + +extern int fflag, rflag, rval; +extern char *fname; diff --git a/usr.bin/tail/forward.c b/usr.bin/tail/forward.c new file mode 100644 index 0000000..8e32cc4 --- /dev/null +++ b/usr.bin/tail/forward.c @@ -0,0 +1,234 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Sze-Tyan Wang. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +static void rlines __P((FILE *, long, struct stat *)); + +/* + * forward -- display the file, from an offset, forward. + * + * There are eight separate cases for this -- regular and non-regular + * files, by bytes or lines and from the beginning or end of the file. + * + * FBYTES byte offset from the beginning of the file + * REG seek + * NOREG read, counting bytes + * + * FLINES line offset from the beginning of the file + * REG read, counting lines + * NOREG read, counting lines + * + * RBYTES byte offset from the end of the file + * REG seek + * NOREG cyclically read characters into a wrap-around buffer + * + * RLINES + * REG mmap the file and step back until reach the correct offset. + * NOREG cyclically read lines into a wrap-around array of buffers + */ +void +forward(fp, style, off, sbp) + FILE *fp; + enum STYLE style; + long off; + struct stat *sbp; +{ + register int ch; + struct timeval second; + fd_set zero; + + switch(style) { + case FBYTES: + if (off == 0) + break; + if (S_ISREG(sbp->st_mode)) { + if (sbp->st_size < off) + off = sbp->st_size; + if (fseek(fp, off, SEEK_SET) == -1) { + ierr(); + return; + } + } else while (off--) + if ((ch = getc(fp)) == EOF) { + if (ferror(fp)) { + ierr(); + return; + } + break; + } + break; + case FLINES: + if (off == 0) + break; + for (;;) { + if ((ch = getc(fp)) == EOF) { + if (ferror(fp)) { + ierr(); + return; + } + break; + } + if (ch == '\n' && !--off) + break; + } + break; + case RBYTES: + if (S_ISREG(sbp->st_mode)) { + if (sbp->st_size >= off && + fseek(fp, -off, SEEK_END) == -1) { + ierr(); + return; + } + } else if (off == 0) { + while (getc(fp) != EOF); + if (ferror(fp)) { + ierr(); + return; + } + } else + bytes(fp, off); + break; + case RLINES: + if (S_ISREG(sbp->st_mode)) + if (!off) { + if (fseek(fp, 0L, SEEK_END) == -1) { + ierr(); + return; + } + } else + rlines(fp, off, sbp); + else if (off == 0) { + while (getc(fp) != EOF); + if (ferror(fp)) { + ierr(); + return; + } + } else + lines(fp, off); + break; + } + + /* + * We pause for one second after displaying any data that has + * accumulated since we read the file. + */ + if (fflag) { + FD_ZERO(&zero); + second.tv_sec = 1; + second.tv_usec = 0; + } + + for (;;) { + while ((ch = getc(fp)) != EOF) + if (putchar(ch) == EOF) + oerr(); + if (ferror(fp)) { + ierr(); + return; + } + (void)fflush(stdout); + if (!fflag) + break; + /* Sleep(3) is eight system calls. Do it fast. */ + if (select(0, &zero, &zero, &zero, &second) == -1) + err(1, "select: %s", strerror(errno)); + clearerr(fp); + } +} + +/* + * rlines -- display the last offset lines of the file. + */ +static void +rlines(fp, off, sbp) + FILE *fp; + long off; + struct stat *sbp; +{ + register off_t size; + register char *p; + char *start; + + if (!(size = sbp->st_size)) + return; + + if (size > SIZE_T_MAX) { + err(0, "%s: %s", fname, strerror(EFBIG)); + return; + } + + if ((start = mmap(NULL, (size_t)size, + PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) { + err(0, "%s: %s", fname, strerror(EFBIG)); + return; + } + + /* Last char is special, ignore whether newline or not. */ + for (p = start + size - 1; --size;) + if (*--p == '\n' && !--off) { + ++p; + break; + } + + /* Set the file pointer to reflect the length displayed. */ + size = sbp->st_size - size; + WR(p, size); + if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) { + ierr(); + return; + } + if (munmap(start, (size_t)sbp->st_size)) { + err(0, "%s: %s", fname, strerror(errno)); + return; + } +} diff --git a/usr.bin/tail/misc.c b/usr.bin/tail/misc.c new file mode 100644 index 0000000..18fd63d --- /dev/null +++ b/usr.bin/tail/misc.c @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Sze-Tyan Wang. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +void +ierr() +{ + err(0, "%s: %s", fname, strerror(errno)); +} + +void +oerr() +{ + err(1, "stdout: %s", strerror(errno)); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(int fatal, const char *fmt, ...) +#else +err(fatal, fmt, va_alist) + int fatal; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "tail: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (fatal) + exit(1); + rval = 1; +} diff --git a/usr.bin/tail/read.c b/usr.bin/tail/read.c new file mode 100644 index 0000000..dc570a3 --- /dev/null +++ b/usr.bin/tail/read.c @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Sze-Tyan Wang. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)read.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +/* + * bytes -- read bytes to an offset from the end and display. + * + * This is the function that reads to a byte offset from the end of the input, + * storing the data in a wrap-around buffer which is then displayed. If the + * rflag is set, the data is displayed in lines in reverse order, and this + * routine has the usual nastiness of trying to find the newlines. Otherwise, + * it is displayed from the character closest to the beginning of the input to + * the end. + */ +void +bytes(fp, off) + register FILE *fp; + off_t off; +{ + register int ch, len, tlen; + register char *ep, *p, *t; + int wrap; + char *sp; + + if ((sp = p = malloc(off)) == NULL) + err(1, "%s", strerror(errno)); + + for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) { + *p = ch; + if (++p == ep) { + wrap = 1; + p = sp; + } + } + if (ferror(fp)) { + ierr(); + return; + } + + if (rflag) { + for (t = p - 1, len = 0; t >= sp; --t, ++len) + if (*t == '\n' && len) { + WR(t + 1, len); + len = 0; + } + if (wrap) { + tlen = len; + for (t = ep - 1, len = 0; t >= p; --t, ++len) + if (*t == '\n') { + if (len) { + WR(t + 1, len); + len = 0; + } + if (tlen) { + WR(sp, tlen); + tlen = 0; + } + } + if (len) + WR(t + 1, len); + if (tlen) + WR(sp, tlen); + } + } else { + if (wrap && (len = ep - p)) + WR(p, len); + if (len = p - sp) + WR(sp, len); + } +} + +/* + * lines -- read lines to an offset from the end and display. + * + * This is the function that reads to a line offset from the end of the input, + * storing the data in an array of buffers which is then displayed. If the + * rflag is set, the data is displayed in lines in reverse order, and this + * routine has the usual nastiness of trying to find the newlines. Otherwise, + * it is displayed from the line closest to the beginning of the input to + * the end. + */ +void +lines(fp, off) + register FILE *fp; + off_t off; +{ + struct { + u_int blen; + u_int len; + char *l; + } *lines; + register int ch; + register char *p; + int blen, cnt, recno, wrap; + char *sp; + + if ((lines = malloc(off * sizeof(*lines))) == NULL) + err(1, "%s", strerror(errno)); + + sp = NULL; + blen = cnt = recno = wrap = 0; + + while ((ch = getc(fp)) != EOF) { + if (++cnt > blen) { + if ((sp = realloc(sp, blen += 1024)) == NULL) + err(1, "%s", strerror(errno)); + p = sp + cnt - 1; + } + *p++ = ch; + if (ch == '\n') { + if (lines[recno].blen < cnt) { + lines[recno].blen = cnt + 256; + if ((lines[recno].l = realloc(lines[recno].l, + lines[recno].blen)) == NULL) + err(1, "%s", strerror(errno)); + } + bcopy(sp, lines[recno].l, lines[recno].len = cnt); + cnt = 0; + p = sp; + if (++recno == off) { + wrap = 1; + recno = 0; + } + } + } + if (ferror(fp)) { + ierr(); + return; + } + if (cnt) { + lines[recno].l = sp; + lines[recno].len = cnt; + if (++recno == off) { + wrap = 1; + recno = 0; + } + } + + if (rflag) { + for (cnt = recno - 1; cnt >= 0; --cnt) + WR(lines[cnt].l, lines[cnt].len); + if (wrap) + for (cnt = off - 1; cnt >= recno; --cnt) + WR(lines[cnt].l, lines[cnt].len); + } else { + if (wrap) + for (cnt = recno; cnt < off; ++cnt) + WR(lines[cnt].l, lines[cnt].len); + for (cnt = 0; cnt < recno; ++cnt) + WR(lines[cnt].l, lines[cnt].len); + } +} diff --git a/usr.bin/tail/reverse.c b/usr.bin/tail/reverse.c new file mode 100644 index 0000000..34cd980 --- /dev/null +++ b/usr.bin/tail/reverse.c @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Sze-Tyan Wang. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "extern.h" + +static void r_buf __P((FILE *)); +static void r_reg __P((FILE *, enum STYLE, long, struct stat *)); + +/* + * reverse -- display input in reverse order by line. + * + * There are six separate cases for this -- regular and non-regular + * files by bytes, lines or the whole file. + * + * BYTES display N bytes + * REG mmap the file and display the lines + * NOREG cyclically read characters into a wrap-around buffer + * + * LINES display N lines + * REG mmap the file and display the lines + * NOREG cyclically read lines into a wrap-around array of buffers + * + * FILE display the entire file + * REG mmap the file and display the lines + * NOREG cyclically read input into a linked list of buffers + */ +void +reverse(fp, style, off, sbp) + FILE *fp; + enum STYLE style; + long off; + struct stat *sbp; +{ + if (style != REVERSE && off == 0) + return; + + if (S_ISREG(sbp->st_mode)) + r_reg(fp, style, off, sbp); + else + switch(style) { + case FBYTES: + case RBYTES: + bytes(fp, off); + break; + case FLINES: + case RLINES: + lines(fp, off); + break; + case REVERSE: + r_buf(fp); + break; + } +} + +/* + * r_reg -- display a regular file in reverse order by line. + */ +static void +r_reg(fp, style, off, sbp) + FILE *fp; + register enum STYLE style; + long off; + struct stat *sbp; +{ + register off_t size; + register int llen; + register char *p; + char *start; + + if (!(size = sbp->st_size)) + return; + + if (size > SIZE_T_MAX) { + err(0, "%s: %s", fname, strerror(EFBIG)); + return; + } + + if ((start = mmap(NULL, (size_t)size, + PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) { + err(0, "%s: %s", fname, strerror(EFBIG)); + return; + } + p = start + size - 1; + + if (style == RBYTES && off < size) + size = off; + + /* Last char is special, ignore whether newline or not. */ + for (llen = 1; --size; ++llen) + if (*--p == '\n') { + WR(p + 1, llen); + llen = 0; + if (style == RLINES && !--off) { + ++p; + break; + } + } + if (llen) + WR(p, llen); + if (munmap(start, (size_t)sbp->st_size)) + err(0, "%s: %s", fname, strerror(errno)); +} + +typedef struct bf { + struct bf *next; + struct bf *prev; + int len; + char *l; +} BF; + +/* + * r_buf -- display a non-regular file in reverse order by line. + * + * This is the function that saves the entire input, storing the data in a + * doubly linked list of buffers and then displays them in reverse order. + * It has the usual nastiness of trying to find the newlines, as there's no + * guarantee that a newline occurs anywhere in the file, let alone in any + * particular buffer. If we run out of memory, input is discarded (and the + * user warned). + */ +static void +r_buf(fp) + FILE *fp; +{ + register BF *mark, *tl, *tr; + register int ch, len, llen; + register char *p; + off_t enomem; + +#define BSZ (128 * 1024) + for (mark = NULL, enomem = 0;;) { + /* + * Allocate a new block and link it into place in a doubly + * linked list. If out of memory, toss the LRU block and + * keep going. + */ + if (enomem || (tl = malloc(sizeof(BF))) == NULL || + (tl->l = malloc(BSZ)) == NULL) { + if (!mark) + err(1, "%s", strerror(errno)); + tl = enomem ? tl->next : mark; + enomem += tl->len; + } else if (mark) { + tl->next = mark; + tl->prev = mark->prev; + mark->prev->next = tl; + mark->prev = tl; + } else + mark->next = mark->prev = (mark = tl); + + /* Fill the block with input data. */ + for (p = tl->l, len = 0; + len < BSZ && (ch = getc(fp)) != EOF; ++len) + *p++ = ch; + + /* + * If no input data for this block and we tossed some data, + * recover it. + */ + if (!len) { + if (enomem) + enomem -= tl->len; + tl = tl->prev; + break; + } + + tl->len = len; + if (ch == EOF) + break; + } + + if (enomem) { + (void)fprintf(stderr, + "tail: warning: %ld bytes discarded\n", enomem); + rval = 1; + } + + /* + * Step through the blocks in the reverse order read. The last char + * is special, ignore whether newline or not. + */ + for (mark = tl;;) { + for (p = tl->l + (len = tl->len) - 1, llen = 0; len--; + --p, ++llen) + if (*p == '\n') { + if (llen) { + WR(p + 1, llen); + llen = 0; + } + if (tl == mark) + continue; + for (tr = tl->next; tr->len; tr = tr->next) { + WR(tr->l, tr->len); + tr->len = 0; + if (tr == mark) + break; + } + } + tl->len = llen; + if ((tl = tl->prev) == mark) + break; + } + tl = tl->next; + if (tl->len) { + WR(tl->l, tl->len); + tl->len = 0; + } + while ((tl = tl->next)->len) { + WR(tl->l, tl->len); + tl->len = 0; + } +} diff --git a/usr.bin/tail/tail.1 b/usr.bin/tail/tail.1 new file mode 100644 index 0000000..02bfba8 --- /dev/null +++ b/usr.bin/tail/tail.1 @@ -0,0 +1,165 @@ +.\" Copyright (c) 1980, 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)tail.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TAIL 1 +.Os BSD 4 +.Sh NAME +.Nm tail +.Nd display the last part of a file +.Sh SYNOPSIS +.Nm tail +.Op Fl f Li | Fl r +.Oo +.Fl b Ar number | +.Fl c Ar number | +.Fl n Ar number +.Oc +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm tail +utility displays the contents of +.Ar file +or, by default, its standard input, to the standard output. +.Pp +The display begins at a byte, line or 512-byte block location in the +input. +Numbers having a leading plus (``+'') sign are relative to the beginning +of the input, for example, +.Dq -c +2 +starts the display at the second +byte of the input. +Numbers having a leading minus (``-'') sign or no explicit sign are +relative to the end of the input, for example, +.Dq -n 2 +displays the last two lines of the input. +The default starting location is +.Dq -n 10 , +or the last 10 lines of the input. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b Ar number +The location is +.Ar number +512-byte blocks. +.It Fl c Ar number +The location is +.Ar number +bytes. +.It Fl f +The +.Fl f +option causes +.Nm tail +to not stop when end of file is reached, but rather to wait for additional +data to be appended to the input. +The +.Fl f +option is ignored if the standard input is a pipe, but not if it is a FIFO. +.It Fl n Ar number +The location is +.Ar number +lines. +.It Fl r +The +.Fl r +option causes the input to be displayed in reverse order, by line. +Additionally, this option changes the meaning of the +.Fl b , +.Fl c +and +.Fl n +options. +When the +.Fl r +option is specified, these options specify the number of bytes, lines +or 512-byte blocks to display, instead of the bytes, lines or blocks +from the beginning or end of the input from which to begin the display. +The default for the +.Fl r +option is to display all of the input. +.El +.Pp +If more than a single file is specified, each file is preceded by a +header consisting of the string +.Dq ==> XXX <== +where +.Dq XXX +is the name of the file. +.Pp +The +.Nm tail +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr cat 1 , +.Xr head 1 , +.Xr sed 1 +.Sh STANDARDS +The +.Nm tail +utility is expected to be a superset of the POSIX 1003.2 +specification. +In particular, the +.Fl b +and +.Fl r +options are extensions to that standard. +.Pp +The historic command line syntax of +.Nm tail +is supported by this implementation. +The only difference between this implementation and historic versions +of +.Nm tail , +once the command line syntax translation has been done, is that the +.Fl b , +.Fl c +and +.Fl n +options modify the +.Fl r +option, i.e. ``-r -c 4'' displays the last 4 characters of the last line +of the input, while the historic tail (using the historic syntax ``-4cr'') +would ignore the +.Fl c +option and display the last 4 lines of the input. +.Sh HISTORY +A +.Nm tail +command appeared in +.At v7 . diff --git a/usr.bin/tail/tail.c b/usr.bin/tail/tail.c new file mode 100644 index 0000000..cc8ea14 --- /dev/null +++ b/usr.bin/tail/tail.c @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Sze-Tyan Wang. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tail.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +int fflag, rflag, rval; +char *fname; + +static void obsolete __P((char **)); +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb; + FILE *fp; + long off; + enum STYLE style; + int ch, first; + char *p; + + /* + * Tail's options are weird. First, -n10 is the same as -n-10, not + * -n+10. Second, the number options are 1 based and not offsets, + * so -n+1 is the first line, and -c-1 is the last byte. Third, the + * number options for the -r option specify the number of things that + * get displayed, not the starting point in the file. The one major + * incompatibility in this version as compared to historical versions + * is that the 'r' option couldn't be modified by the -lbc options, + * i.e. it was always done in lines. This version treats -rc as a + * number of characters in reverse order. Finally, the default for + * -r is the entire file, not 10 lines. + */ +#define ARG(units, forward, backward) { \ + if (style) \ + usage(); \ + off = strtol(optarg, &p, 10) * (units); \ + if (*p) \ + err(1, "illegal offset -- %s", optarg); \ + switch(optarg[0]) { \ + case '+': \ + if (off) \ + off -= (units); \ + style = (forward); \ + break; \ + case '-': \ + off = -off; \ + /* FALLTHROUGH */ \ + default: \ + style = (backward); \ + break; \ + } \ +} + + obsolete(argv); + style = NOTSET; + while ((ch = getopt(argc, argv, "b:c:fn:r")) != EOF) + switch(ch) { + case 'b': + ARG(512, FBYTES, RBYTES); + break; + case 'c': + ARG(1, FBYTES, RBYTES); + break; + case 'f': + fflag = 1; + break; + case 'n': + ARG(1, FLINES, RLINES); + break; + case 'r': + rflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (fflag && argc > 1) + err(1, "-f option only appropriate for a single file"); + + /* + * If displaying in reverse, don't permit follow option, and convert + * style values. + */ + if (rflag) { + if (fflag) + usage(); + if (style == FBYTES) + style = RBYTES; + else if (style == FLINES) + style = RLINES; + } + + /* + * If style not specified, the default is the whole file for -r, and + * the last 10 lines if not -r. + */ + if (style == NOTSET) + if (rflag) { + off = 0; + style = REVERSE; + } else { + off = 10; + style = RLINES; + } + + if (*argv) + for (first = 1; fname = *argv++;) { + if ((fp = fopen(fname, "r")) == NULL || + fstat(fileno(fp), &sb)) { + ierr(); + continue; + } + if (argc > 1) { + (void)printf("%s==> %s <==\n", + first ? "" : "\n", fname); + first = 0; + (void)fflush(stdout); + } + + if (rflag) + reverse(fp, style, off, &sb); + else + forward(fp, style, off, &sb); + (void)fclose(fp); + } + else { + fname = "stdin"; + + if (fstat(fileno(stdin), &sb)) { + ierr(); + exit(1); + } + + /* + * Determine if input is a pipe. 4.4BSD will set the SOCKET + * bit in the st_mode field for pipes. Fix this then. + */ + if (lseek(fileno(stdin), (off_t)0, SEEK_CUR) == -1 && + errno == ESPIPE) { + errno = 0; + fflag = 0; /* POSIX.2 requires this. */ + } + + if (rflag) + reverse(stdin, style, off, &sb); + else + forward(stdin, style, off, &sb); + } + exit(rval); +} + +/* + * Convert the obsolete argument form into something that getopt can handle. + * This means that anything of the form [+-][0-9][0-9]*[lbc][fr] that isn't + * the option argument for a -b, -c or -n option gets converted. + */ +static void +obsolete(argv) + char *argv[]; +{ + register char *ap, *p, *t; + int len; + char *start; + + while (ap = *++argv) { + /* Return if "--" or not an option of any form. */ + if (ap[0] != '-') { + if (ap[0] != '+') + return; + } else if (ap[1] == '-') + return; + + switch(*++ap) { + /* Old-style option. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + + /* Malloc space for dash, new option and argument. */ + len = strlen(*argv); + if ((start = p = malloc(len + 3)) == NULL) + err(1, "%s", strerror(errno)); + *p++ = '-'; + + /* + * Go to the end of the option argument. Save off any + * trailing options (-3lf) and translate any trailing + * output style characters. + */ + t = *argv + len - 1; + if (*t == 'f' || *t == 'r') { + *p++ = *t; + *t-- = '\0'; + } + switch(*t) { + case 'b': + *p++ = 'b'; + *t = '\0'; + break; + case 'c': + *p++ = 'c'; + *t = '\0'; + break; + case 'l': + *t = '\0'; + /* FALLTHROUGH */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *p++ = 'n'; + break; + default: + err(1, "illegal option -- %s", *argv); + } + *p++ = *argv[0]; + (void)strcpy(p, ap); + *argv = start; + continue; + + /* + * Options w/ arguments, skip the argument and continue + * with the next option. + */ + case 'b': + case 'c': + case 'n': + if (!ap[1]) + ++argv; + /* FALLTHROUGH */ + /* Options w/o arguments, continue with the next option. */ + case 'f': + case 'r': + continue; + + /* Illegal option, return and let getopt handle it. */ + default: + return; + } + } +} + +static void +usage() +{ + (void)fprintf(stderr, + "usage: tail [-f | -r] [-b # | -c # | -n #] [file ...]\n"); + exit(1); +} diff --git a/usr.bin/talk/Makefile b/usr.bin/talk/Makefile new file mode 100644 index 0000000..d86cd02 --- /dev/null +++ b/usr.bin/talk/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= talk +DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBCOMPAT} +LDADD= -lcurses -ltermlib -lcompat +SRCS= ctl.c ctl_transact.c display.c get_addrs.c get_names.c \ + init_disp.c invite.c io.c look_up.c msgs.c talk.c + +.include diff --git a/usr.bin/talk/ctl.c b/usr.bin/talk/ctl.c new file mode 100644 index 0000000..250cbc1 --- /dev/null +++ b/usr.bin/talk/ctl.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)ctl.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This file handles haggling with the various talk daemons to + * get a socket to talk to. sockt is opened and connected in + * the progress + */ + +#include +#include +#include +#include +#include "talk.h" +#include "talk_ctl.h" + +struct sockaddr_in daemon_addr = { sizeof(daemon_addr), AF_INET }; +struct sockaddr_in ctl_addr = { sizeof(ctl_addr), AF_INET }; +struct sockaddr_in my_addr = { sizeof(my_addr), AF_INET }; + + /* inet addresses of the two machines */ +struct in_addr my_machine_addr; +struct in_addr his_machine_addr; + +u_short daemon_port; /* port number of the talk daemon */ + +int ctl_sockt; +int sockt; +int invitation_waiting = 0; + +CTL_MSG msg; + +open_sockt() +{ + int length; + + my_addr.sin_addr = my_machine_addr; + my_addr.sin_port = 0; + sockt = socket(AF_INET, SOCK_STREAM, 0); + if (sockt <= 0) + p_error("Bad socket"); + if (bind(sockt, (struct sockaddr *)&my_addr, sizeof(my_addr)) != 0) + p_error("Binding local socket"); + length = sizeof(my_addr); + if (getsockname(sockt, (struct sockaddr *)&my_addr, &length) == -1) + p_error("Bad address for socket"); +} + +/* open the ctl socket */ +open_ctl() +{ + int length; + + ctl_addr.sin_port = 0; + ctl_addr.sin_addr = my_machine_addr; + ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0); + if (ctl_sockt <= 0) + p_error("Bad socket"); + if (bind(ctl_sockt, + (struct sockaddr *)&ctl_addr, sizeof(ctl_addr)) != 0) + p_error("Couldn't bind to control socket"); + length = sizeof(ctl_addr); + if (getsockname(ctl_sockt, + (struct sockaddr *)&ctl_addr, &length) == -1) + p_error("Bad address for ctl socket"); +} + +/* print_addr is a debug print routine */ +print_addr(addr) + struct sockaddr_in addr; +{ + int i; + + printf("addr = %x, port = %o, family = %o zero = ", + addr.sin_addr, addr.sin_port, addr.sin_family); + for (i = 0; i<8;i++) + printf("%o ", (int)addr.sin_zero[i]); + putchar('\n'); +} diff --git a/usr.bin/talk/ctl_transact.c b/usr.bin/talk/ctl_transact.c new file mode 100644 index 0000000..73ee23b --- /dev/null +++ b/usr.bin/talk/ctl_transact.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)ctl_transact.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include "talk_ctl.h" + +#define CTL_WAIT 2 /* time to wait for a response, in seconds */ + +/* + * SOCKDGRAM is unreliable, so we must repeat messages if we have + * not recieved an acknowledgement within a reasonable amount + * of time + */ +ctl_transact(target, msg, type, rp) + struct in_addr target; + CTL_MSG msg; + int type; + CTL_RESPONSE *rp; +{ + int read_mask, ctl_mask, nready, cc; + struct timeval wait; + + msg.type = type; + daemon_addr.sin_addr = target; + daemon_addr.sin_port = daemon_port; + ctl_mask = 1 << ctl_sockt; + + /* + * Keep sending the message until a response of + * the proper type is obtained. + */ + do { + wait.tv_sec = CTL_WAIT; + wait.tv_usec = 0; + /* resend message until a response is obtained */ + do { + cc = sendto(ctl_sockt, (char *)&msg, sizeof (msg), 0, + (struct sockaddr *)&daemon_addr, + sizeof (daemon_addr)); + if (cc != sizeof (msg)) { + if (errno == EINTR) + continue; + p_error("Error on write to talk daemon"); + } + read_mask = ctl_mask; + nready = select(32, &read_mask, 0, 0, &wait); + if (nready < 0) { + if (errno == EINTR) + continue; + p_error("Error waiting for daemon response"); + } + } while (nready == 0); + /* + * Keep reading while there are queued messages + * (this is not necessary, it just saves extra + * request/acknowledgements being sent) + */ + do { + cc = recv(ctl_sockt, (char *)rp, sizeof (*rp), 0); + if (cc < 0) { + if (errno == EINTR) + continue; + p_error("Error on read from talk daemon"); + } + read_mask = ctl_mask; + /* an immediate poll */ + timerclear(&wait); + nready = select(32, &read_mask, 0, 0, &wait); + } while (nready > 0 && (rp->vers != TALK_VERSION || + rp->type != type)); + } while (rp->vers != TALK_VERSION || rp->type != type); + rp->id_num = ntohl(rp->id_num); + rp->addr.sa_family = ntohs(rp->addr.sa_family); +} diff --git a/usr.bin/talk/display.c b/usr.bin/talk/display.c new file mode 100644 index 0000000..e5c059e --- /dev/null +++ b/usr.bin/talk/display.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)display.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * The window 'manager', initializes curses and handles the actual + * displaying of text + */ +#include "talk.h" + +xwin_t my_win; +xwin_t his_win; +WINDOW *line_win; + +int curses_initialized = 0; + +/* + * max HAS to be a function, it is called with + * a argument of the form --foo at least once. + */ +max(a,b) + int a, b; +{ + + return (a > b ? a : b); +} + +/* + * Display some text on somebody's window, processing some control + * characters while we are at it. + */ +display(win, text, size) + register xwin_t *win; + register char *text; + int size; +{ + register int i; + char cch; + + for (i = 0; i < size; i++) { + if (*text == '\n') { + xscroll(win, 0); + text++; + continue; + } + /* erase character */ + if (*text == win->cerase) { + wmove(win->x_win, win->x_line, max(--win->x_col, 0)); + getyx(win->x_win, win->x_line, win->x_col); + waddch(win->x_win, ' '); + wmove(win->x_win, win->x_line, win->x_col); + getyx(win->x_win, win->x_line, win->x_col); + text++; + continue; + } + /* + * On word erase search backwards until we find + * the beginning of a word or the beginning of + * the line. + */ + if (*text == win->werase) { + int endcol, xcol, i, c; + + endcol = win->x_col; + xcol = endcol - 1; + while (xcol >= 0) { + c = readwin(win->x_win, win->x_line, xcol); + if (c != ' ') + break; + xcol--; + } + while (xcol >= 0) { + c = readwin(win->x_win, win->x_line, xcol); + if (c == ' ') + break; + xcol--; + } + wmove(win->x_win, win->x_line, xcol + 1); + for (i = xcol + 1; i < endcol; i++) + waddch(win->x_win, ' '); + wmove(win->x_win, win->x_line, xcol + 1); + getyx(win->x_win, win->x_line, win->x_col); + text++; + continue; + } + /* line kill */ + if (*text == win->kill) { + wmove(win->x_win, win->x_line, 0); + wclrtoeol(win->x_win); + getyx(win->x_win, win->x_line, win->x_col); + text++; + continue; + } + if (*text == '\f') { + if (win == &my_win) + wrefresh(curscr); + text++; + continue; + } + if (win->x_col == COLS-1) { + /* check for wraparound */ + xscroll(win, 0); + } + if (*text < ' ' && *text != '\t') { + waddch(win->x_win, '^'); + getyx(win->x_win, win->x_line, win->x_col); + if (win->x_col == COLS-1) /* check for wraparound */ + xscroll(win, 0); + cch = (*text & 63) + 64; + waddch(win->x_win, cch); + } else + waddch(win->x_win, *text); + getyx(win->x_win, win->x_line, win->x_col); + text++; + } + wrefresh(win->x_win); +} + +/* + * Read the character at the indicated position in win + */ +readwin(win, line, col) + WINDOW *win; +{ + int oldline, oldcol; + register int c; + + getyx(win, oldline, oldcol); + wmove(win, line, col); + c = winch(win); + wmove(win, oldline, oldcol); + return (c); +} + +/* + * Scroll a window, blanking out the line following the current line + * so that the current position is obvious + */ +xscroll(win, flag) + register xwin_t *win; + int flag; +{ + + if (flag == -1) { + wmove(win->x_win, 0, 0); + win->x_line = 0; + win->x_col = 0; + return; + } + win->x_line = (win->x_line + 1) % win->x_nlines; + win->x_col = 0; + wmove(win->x_win, win->x_line, win->x_col); + wclrtoeol(win->x_win); + wmove(win->x_win, (win->x_line + 1) % win->x_nlines, win->x_col); + wclrtoeol(win->x_win); + wmove(win->x_win, win->x_line, win->x_col); +} diff --git a/usr.bin/talk/get_addrs.c b/usr.bin/talk/get_addrs.c new file mode 100644 index 0000000..b9db4a6 --- /dev/null +++ b/usr.bin/talk/get_addrs.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)get_addrs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include "talk_ctl.h" + +get_addrs(my_machine_name, his_machine_name) + char *my_machine_name, *his_machine_name; +{ + struct hostent *hp; + struct servent *sp; + + msg.pid = htonl(getpid()); + /* look up the address of the local host */ + hp = gethostbyname(my_machine_name); + if (hp == NULL) { + fprintf(stderr, "talk: %s: ", my_machine_name); + herror((char *)NULL); + exit(-1); + } + bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length); + /* + * If the callee is on-machine, just copy the + * network address, otherwise do a lookup... + */ + if (strcmp(his_machine_name, my_machine_name)) { + hp = gethostbyname(his_machine_name); + if (hp == NULL) { + fprintf(stderr, "talk: %s: ", his_machine_name); + herror((char *)NULL); + exit(-1); + } + bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length); + } else + his_machine_addr = my_machine_addr; + /* find the server's port */ + sp = getservbyname("ntalk", "udp"); + if (sp == 0) { + fprintf(stderr, "talk: %s/%s: service is not registered.\n", + "ntalk", "udp"); + exit(-1); + } + daemon_port = sp->s_port; +} diff --git a/usr.bin/talk/get_names.c b/usr.bin/talk/get_names.c new file mode 100644 index 0000000..9d3cc04 --- /dev/null +++ b/usr.bin/talk/get_names.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)get_names.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "talk.h" + +char *getlogin(); +char *ttyname(); +char *rindex(); +extern CTL_MSG msg; + +/* + * Determine the local and remote user, tty, and machines + */ +get_names(argc, argv) + int argc; + char *argv[]; +{ + char hostname[MAXHOSTNAMELEN]; + char *his_name, *my_name; + char *my_machine_name, *his_machine_name; + char *my_tty, *his_tty; + register char *cp; + + if (argc < 2 ) { + printf("Usage: talk user [ttyname]\n"); + exit(-1); + } + if (!isatty(0)) { + printf("Standard input must be a tty, not a pipe or a file\n"); + exit(-1); + } + if ((my_name = getlogin()) == NULL) { + struct passwd *pw; + + if ((pw = getpwuid(getuid())) == NULL) { + printf("You don't exist. Go away.\n"); + exit(-1); + } + my_name = pw->pw_name; + } + gethostname(hostname, sizeof (hostname)); + my_machine_name = hostname; + /* check for, and strip out, the machine name of the target */ + for (cp = argv[1]; *cp && !index("@:!.", *cp); cp++) + ; + if (*cp == '\0') { + /* this is a local to local talk */ + his_name = argv[1]; + his_machine_name = my_machine_name; + } else { + if (*cp++ == '@') { + /* user@host */ + his_name = argv[1]; + his_machine_name = cp; + } else { + /* host.user or host!user or host:user */ + his_name = cp; + his_machine_name = argv[1]; + } + *--cp = '\0'; + } + if (argc > 2) + his_tty = argv[2]; /* tty name is arg 2 */ + else + his_tty = ""; + get_addrs(my_machine_name, his_machine_name); + /* + * Initialize the message template. + */ + msg.vers = TALK_VERSION; + msg.addr.sa_family = htons(AF_INET); + msg.ctl_addr.sa_family = htons(AF_INET); + msg.id_num = htonl(0); + strncpy(msg.l_name, my_name, NAME_SIZE); + msg.l_name[NAME_SIZE - 1] = '\0'; + strncpy(msg.r_name, his_name, NAME_SIZE); + msg.r_name[NAME_SIZE - 1] = '\0'; + strncpy(msg.r_tty, his_tty, TTY_SIZE); + msg.r_tty[TTY_SIZE - 1] = '\0'; +} diff --git a/usr.bin/talk/init_disp.c b/usr.bin/talk/init_disp.c new file mode 100644 index 0000000..517e51c --- /dev/null +++ b/usr.bin/talk/init_disp.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)init_disp.c 8.2 (Berkeley) 2/16/94"; +#endif /* not lint */ + +/* + * Initialization code for the display package, + * as well as the signal handling routines. + */ + +#include +#include + +#include +#include +#include "talk.h" + +/* + * Set up curses, catch the appropriate signals, + * and build the various windows. + */ +init_display() +{ + void sig_sent(); + struct sigvec sigv; + + if (initscr() == NULL) + errx(1, "Terminal type unset or lacking necessary features."); + (void) sigvec(SIGTSTP, (struct sigvec *)0, &sigv); + sigv.sv_mask |= sigmask(SIGALRM); + (void) sigvec(SIGTSTP, &sigv, (struct sigvec *)0); + curses_initialized = 1; + clear(); + refresh(); + noecho(); + crmode(); + signal(SIGINT, sig_sent); + signal(SIGPIPE, sig_sent); + /* curses takes care of ^Z */ + my_win.x_nlines = LINES / 2; + my_win.x_ncols = COLS; + my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0); + scrollok(my_win.x_win, FALSE); + wclear(my_win.x_win); + + his_win.x_nlines = LINES / 2 - 1; + his_win.x_ncols = COLS; + his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols, + my_win.x_nlines+1, 0); + scrollok(his_win.x_win, FALSE); + wclear(his_win.x_win); + + line_win = newwin(1, COLS, my_win.x_nlines, 0); + box(line_win, '-', '-'); + wrefresh(line_win); + /* let them know we are working on it */ + current_state = "No connection yet"; +} + +/* + * Trade edit characters with the other talk. By agreement + * the first three characters each talk transmits after + * connection are the three edit characters. + */ +set_edit_chars() +{ + char buf[3]; + int cc; + struct sgttyb tty; + struct ltchars ltc; + + ioctl(0, TIOCGETP, &tty); + ioctl(0, TIOCGLTC, (struct sgttyb *)<c); + my_win.cerase = tty.sg_erase; + my_win.kill = tty.sg_kill; + if (ltc.t_werasc == (char) -1) + my_win.werase = '\027'; /* control W */ + else + my_win.werase = ltc.t_werasc; + buf[0] = my_win.cerase; + buf[1] = my_win.kill; + buf[2] = my_win.werase; + cc = write(sockt, buf, sizeof(buf)); + if (cc != sizeof(buf) ) + p_error("Lost the connection"); + cc = read(sockt, buf, sizeof(buf)); + if (cc != sizeof(buf) ) + p_error("Lost the connection"); + his_win.cerase = buf[0]; + his_win.kill = buf[1]; + his_win.werase = buf[2]; +} + +void +sig_sent() +{ + + message("Connection closing. Exiting"); + quit(); +} + +/* + * All done talking...hang up the phone and reset terminal thingy's + */ +quit() +{ + + if (curses_initialized) { + wmove(his_win.x_win, his_win.x_nlines-1, 0); + wclrtoeol(his_win.x_win); + wrefresh(his_win.x_win); + endwin(); + } + if (invitation_waiting) + send_delete(); + exit(0); +} diff --git a/usr.bin/talk/invite.c b/usr.bin/talk/invite.c new file mode 100644 index 0000000..ae73539 --- /dev/null +++ b/usr.bin/talk/invite.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)invite.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "talk_ctl.h" +#include "talk.h" + +/* + * There wasn't an invitation waiting, so send a request containing + * our sockt address to the remote talk daemon so it can invite + * him + */ + +/* + * The msg.id's for the invitations + * on the local and remote machines. + * These are used to delete the + * invitations. + */ +int local_id, remote_id; +void re_invite(); +jmp_buf invitebuf; + +invite_remote() +{ + int nfd, read_mask, template, new_sockt; + struct itimerval itimer; + CTL_RESPONSE response; + + itimer.it_value.tv_sec = RING_WAIT; + itimer.it_value.tv_usec = 0; + itimer.it_interval = itimer.it_value; + if (listen(sockt, 5) != 0) + p_error("Error on attempt to listen for caller"); +#ifdef MSG_EOR + /* copy new style sockaddr to old, swap family (short in old) */ + msg.addr = *(struct osockaddr *)&my_addr; /* XXX new to old style*/ + msg.addr.sa_family = htons(my_addr.sin_family); +#else + msg.addr = *(struct sockaddr *)&my_addr; +#endif + msg.id_num = htonl(-1); /* an impossible id_num */ + invitation_waiting = 1; + announce_invite(); + /* + * Shut off the automatic messages for a while, + * so we can use the interupt timer to resend the invitation + */ + end_msgs(); + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); + message("Waiting for your party to respond"); + signal(SIGALRM, re_invite); + (void) setjmp(invitebuf); + while ((new_sockt = accept(sockt, 0, 0)) < 0) { + if (errno == EINTR) + continue; + p_error("Unable to connect with your party"); + } + close(sockt); + sockt = new_sockt; + + /* + * Have the daemons delete the invitations now that we + * have connected. + */ + current_state = "Waiting for your party to respond"; + start_msgs(); + + msg.id_num = htonl(local_id); + ctl_transact(my_machine_addr, msg, DELETE, &response); + msg.id_num = htonl(remote_id); + ctl_transact(his_machine_addr, msg, DELETE, &response); + invitation_waiting = 0; +} + +/* + * Routine called on interupt to re-invite the callee + */ +void +re_invite() +{ + + message("Ringing your party again"); + current_line++; + /* force a re-announce */ + msg.id_num = htonl(remote_id + 1); + announce_invite(); + longjmp(invitebuf, 1); +} + +static char *answers[] = { + "answer #0", /* SUCCESS */ + "Your party is not logged on", /* NOT_HERE */ + "Target machine is too confused to talk to us", /* FAILED */ + "Target machine does not recognize us", /* MACHINE_UNKNOWN */ + "Your party is refusing messages", /* PERMISSION_REFUSED */ + "Target machine can not handle remote talk", /* UNKNOWN_REQUEST */ + "Target machine indicates protocol mismatch", /* BADVERSION */ + "Target machine indicates protocol botch (addr)",/* BADADDR */ + "Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */ +}; +#define NANSWERS (sizeof (answers) / sizeof (answers[0])) + +/* + * Transmit the invitation and process the response + */ +announce_invite() +{ + CTL_RESPONSE response; + + current_state = "Trying to connect to your party's talk daemon"; + ctl_transact(his_machine_addr, msg, ANNOUNCE, &response); + remote_id = response.id_num; + if (response.answer != SUCCESS) { + if (response.answer < NANSWERS) + message(answers[response.answer]); + quit(); + } + /* leave the actual invitation on my talk daemon */ + ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response); + local_id = response.id_num; +} + +/* + * Tell the daemon to remove your invitation + */ +send_delete() +{ + + msg.type = DELETE; + /* + * This is just a extra clean up, so just send it + * and don't wait for an answer + */ + msg.id_num = htonl(remote_id); + daemon_addr.sin_addr = his_machine_addr; + if (sendto(ctl_sockt, &msg, sizeof (msg), 0, + (struct sockaddr *)&daemon_addr, + sizeof (daemon_addr)) != sizeof(msg)) + perror("send_delete (remote)"); + msg.id_num = htonl(local_id); + daemon_addr.sin_addr = my_machine_addr; + if (sendto(ctl_sockt, &msg, sizeof (msg), 0, + (struct sockaddr *)&daemon_addr, + sizeof (daemon_addr)) != sizeof (msg)) + perror("send_delete (local)"); +} diff --git a/usr.bin/talk/io.c b/usr.bin/talk/io.c new file mode 100644 index 0000000..5ba6f97 --- /dev/null +++ b/usr.bin/talk/io.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)io.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This file contains the I/O handling and the exchange of + * edit characters. This connection itself is established in + * ctl.c + */ + +#include +#include +#include +#include +#include +#include "talk.h" + +#define A_LONG_TIME 10000000 +#define STDIN_MASK (1< +#include +#include +#include +#include +#include "talk_ctl.h" +#include "talk.h" + +/* + * See if the local daemon has an invitation for us. + */ +check_local() +{ + CTL_RESPONSE response; + register CTL_RESPONSE *rp = &response; + + /* the rest of msg was set up in get_names */ +#ifdef MSG_EOR + /* copy new style sockaddr to old, swap family (short in old) */ + msg.ctl_addr = *(struct osockaddr *)&ctl_addr; + msg.ctl_addr.sa_family = htons(ctl_addr.sin_family); +#else + msg.ctl_addr = *(struct sockaddr *)&ctl_addr; +#endif + /* must be initiating a talk */ + if (!look_for_invite(rp)) + return (0); + /* + * There was an invitation waiting for us, + * so connect with the other (hopefully waiting) party + */ + current_state = "Waiting to connect with caller"; + do { + if (rp->addr.sa_family != AF_INET) + p_error("Response uses invalid network address"); + errno = 0; + if (connect(sockt, + (struct sockaddr *)&rp->addr, sizeof (rp->addr)) != -1) + return (1); + } while (errno == EINTR); + if (errno == ECONNREFUSED) { + /* + * The caller gave up, but his invitation somehow + * was not cleared. Clear it and initiate an + * invitation. (We know there are no newer invitations, + * the talkd works LIFO.) + */ + ctl_transact(his_machine_addr, msg, DELETE, rp); + close(sockt); + open_sockt(); + return (0); + } + p_error("Unable to connect with initiator"); + /*NOTREACHED*/ +} + +/* + * Look for an invitation on 'machine' + */ +look_for_invite(rp) + CTL_RESPONSE *rp; +{ + struct in_addr machine_addr; + + current_state = "Checking for invitation on caller's machine"; + ctl_transact(his_machine_addr, msg, LOOK_UP, rp); + /* the switch is for later options, such as multiple invitations */ + switch (rp->answer) { + + case SUCCESS: + msg.id_num = htonl(rp->id_num); + return (1); + + default: + /* there wasn't an invitation waiting for us */ + return (0); + } +} diff --git a/usr.bin/talk/msgs.c b/usr.bin/talk/msgs.c new file mode 100644 index 0000000..733c207 --- /dev/null +++ b/usr.bin/talk/msgs.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * A package to display what is happening every MSG_INTERVAL seconds + * if we are slow connecting. + */ + +#include +#include +#include +#include "talk.h" + +#define MSG_INTERVAL 4 + +char *current_state; +int current_line = 0; + +void +disp_msg() +{ + message(current_state); +} + +start_msgs() +{ + struct itimerval itimer; + + message(current_state); + signal(SIGALRM, disp_msg); + itimer.it_value.tv_sec = itimer.it_interval.tv_sec = MSG_INTERVAL; + itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); +} + +end_msgs() +{ + struct itimerval itimer; + + timerclear(&itimer.it_value); + timerclear(&itimer.it_interval); + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); + signal(SIGALRM, SIG_DFL); +} diff --git a/usr.bin/talk/talk.1 b/usr.bin/talk/talk.1 new file mode 100644 index 0000000..18c3304 --- /dev/null +++ b/usr.bin/talk/talk.1 @@ -0,0 +1,129 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)talk.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TALK 1 +.Os BSD 4.2 +.Sh NAME +.Nm talk +.Nd talk to another user +.Sh SYNOPSIS +.Nm talk +.Ar person +.Op Ar ttyname +.Sh DESCRIPTION +.Nm Talk +is a visual communication program which copies lines from your +terminal to that of another user. +.Pp +Options available: +.Bl -tag -width ttyname +.It Ar person +If you wish to talk to someone on your own machine, then +.Ar person +is just the person's login name. If you wish to talk to a user on +another host, then +.Ar person +is of the form +.Ql user@host . +.It Ar ttyname +If you wish to talk to a user who is logged in more than once, the +.Ar ttyname +argument may be used to indicate the appropriate terminal +name, where +.Ar ttyname +is of the form +.Ql ttyXX . +.El +.Pp +When first called, +.Nm talk +sends the message +.Bd -literal -offset indent -compact +Message from TalkDaemon@his_machine... +talk: connection requested by your_name@your_machine. +talk: respond with: talk your_name@your_machine +.Ed +.Pp +to the user you wish to talk to. At this point, the recipient +of the message should reply by typing +.Pp +.Dl talk \ your_name@your_machine +.Pp +It doesn't matter from which machine the recipient replies, as +long as his login-name is the same. Once communication is established, +the two parties may type simultaneously, with their output appearing +in separate windows. Typing control-L +.Ql ^L +will cause the screen to +be reprinted, while your erase, kill, and word kill characters will +behave normally. To exit, just type your interrupt character; +.Nm talk +then moves the cursor to the bottom of the screen and restores the +terminal to its previous state. +.Pp +Permission to talk may be denied or granted by use of the +.Xr mesg 1 +command. At the outset talking is allowed. Certain commands, in +particular +.Xr nroff 1 +and +.Xr pr 1 , +disallow messages in order to +prevent messy output. +.Pp +.Sh FILES +.Bl -tag -width /var/run/utmp -compact +.It Pa /etc/hosts +to find the recipient's machine +.It Pa /var/run/utmp +to find the recipient's tty +.El +.Sh SEE ALSO +.Xr mail 1 , +.Xr mesg 1 , +.Xr who 1 , +.Xr write 1 +.Sh BUGS +The version of +.Xr talk 1 +released with +.Bx 4.3 +uses a protocol that +is incompatible with the protocol used in the version released with +.Bx 4.2 . +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr.bin/talk/talk.c b/usr.bin/talk/talk.c new file mode 100644 index 0000000..702df16 --- /dev/null +++ b/usr.bin/talk/talk.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)talk.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "talk.h" + +/* + * talk: A visual form of write. Using sockets, a two way + * connection is set up between the two people talking. + * With the aid of curses, the screen is split into two + * windows, and each users text is added to the window, + * one character at a time... + * + * Written by Kipp Hickman + * + * Modified to run under 4.1a by Clem Cole and Peter Moore + * Modified to run between hosts by Peter Moore, 8/19/82 + * Modified to run under 4.1c by Peter Moore 3/17/83 + */ + +main(argc, argv) + int argc; + char *argv[]; +{ + get_names(argc, argv); + init_display(); + open_ctl(); + open_sockt(); + start_msgs(); + if (!check_local()) + invite_remote(); + end_msgs(); + set_edit_chars(); + talk(); +} diff --git a/usr.bin/talk/talk.h b/usr.bin/talk/talk.h new file mode 100644 index 0000000..98a7118 --- /dev/null +++ b/usr.bin/talk/talk.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)talk.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +extern int sockt; +extern int curses_initialized; +extern int invitation_waiting; + +extern char *current_state; +extern int current_line; + +typedef struct xwin { + WINDOW *x_win; + int x_nlines; + int x_ncols; + int x_line; + int x_col; + char kill; + char cerase; + char werase; +} xwin_t; + +extern xwin_t my_win; +extern xwin_t his_win; +extern WINDOW *line_win; diff --git a/usr.bin/talk/talk_ctl.h b/usr.bin/talk/talk_ctl.h new file mode 100644 index 0000000..91c75d0 --- /dev/null +++ b/usr.bin/talk/talk_ctl.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1983, 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. + * + * @(#)talk_ctl.h 8.1 (Berkeley) 6/6/93 + */ + +extern struct sockaddr_in daemon_addr; +extern struct sockaddr_in ctl_addr; +extern struct sockaddr_in my_addr; +extern struct in_addr my_machine_addr; +extern struct in_addr his_machine_addr; +extern u_short daemon_port; +extern int ctl_sockt; +extern CTL_MSG msg; diff --git a/usr.bin/tcopy/Makefile b/usr.bin/tcopy/Makefile new file mode 100644 index 0000000..5a42f6d --- /dev/null +++ b/usr.bin/tcopy/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tcopy + +.include diff --git a/usr.bin/tcopy/pathnames.h b/usr.bin/tcopy/pathnames.h new file mode 100644 index 0000000..ddf4286 --- /dev/null +++ b/usr.bin/tcopy/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_DEFTAPE "/dev/rmt0" diff --git a/usr.bin/tcopy/tcopy.1 b/usr.bin/tcopy/tcopy.1 new file mode 100644 index 0000000..d5554cd --- /dev/null +++ b/usr.bin/tcopy/tcopy.1 @@ -0,0 +1,89 @@ +.\" Copyright (c) 1985, 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. +.\" +.\" @(#)tcopy.1 8.2 (Berkeley) 4/17/94 +.\" +.Dd April 17, 1994 +.Dt TCOPY 1 +.Os BSD 4.3 +.Sh NAME +.Nm tcopy +.Nd copy and/or verify mag tapes +.Sh SYNOPSIS +.Nm tcopy +.Op Fl cvx +.Op Fl s Ar maxblk +.Oo Ar src Op Ar dest +.Oc +.Sh DESCRIPTION +.Nm Tcopy +is designed to copy magnetic tapes. The only assumption made +about the tape is that there are two tape marks at the end. +.Nm Tcopy +with only a source tape +.Pf ( Ar rmt0 +by default) specified will print +information about the sizes of records and tape files. If a destination +is specified a copy will be made of the source tape. The blocking on the +destination tape will be identical to that used on the source tape. Copying +a tape will yield the same output as if just printing the sizes. +.Pp +Options: +.Bl -tag -width s_maxblk +.It Fl c +Copy +.Ar src +to +.Ar dest +and then verify that the two tapes are identical. +.It Fl s Ar maxblk +Specify a maximum block size, +.Ar maxblk . +.It Fl v +Given the two tapes, +.ar src +and +.Ar dest +verify that they are identical. +.It Fl x +Output all informational messages to the standard error. +This option is useful when +.Ar dest +is +.Pa /dev/stdout . +.El +.Sh SEE ALSO +.Xr mtio 4 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/tcopy/tcopy.c b/usr.bin/tcopy/tcopy.c new file mode 100644 index 0000000..e717499 --- /dev/null +++ b/usr.bin/tcopy/tcopy.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 1985, 1987, 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 copyright[] = +"@(#) Copyright (c) 1985, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +#define MAXREC (64 * 1024) +#define NOCOUNT (-2) + +int filen, guesslen, maxblk = MAXREC; +long lastrec, record, size, tsize; +FILE *msg = stdout; + +void *getspace __P((int)); +void intr __P((int)); +void usage __P((void)); +void verify __P((int, int, char *)); +void writeop __P((int, int)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int lastnread, nread, nw, inp, outp; + enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; + sig_t oldsig; + int ch, needeof; + char *buff, *inf; + + guesslen = 1; + while ((ch = getopt(argc, argv, "cs:vx")) != EOF) + switch((char)ch) { + case 'c': + op = COPYVERIFY; + break; + case 's': + maxblk = atoi(optarg); + if (maxblk <= 0) { + fprintf(stderr, "tcopy: illegal block size\n"); + usage(); + } + guesslen = 0; + break; + case 'v': + op = VERIFY; + break; + case 'x': + msg = stderr; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + if (op != READ) + usage(); + inf = _PATH_DEFTAPE; + break; + case 1: + if (op != READ) + usage(); + inf = argv[0]; + break; + case 2: + if (op == READ) + op = COPY; + inf = argv[0]; + if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : + op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { + perror(argv[1]); + exit(3); + } + break; + default: + usage(); + } + + if ((inp = open(inf, O_RDONLY, 0)) < 0) { + perror(inf); + exit(1); + } + + buff = getspace(maxblk); + + if (op == VERIFY) { + verify(inp, outp, buff); + exit(0); + } + + if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) + (void) signal(SIGINT, intr); + + needeof = 0; + for (lastnread = NOCOUNT;;) { + if ((nread = read(inp, buff, maxblk)) == -1) { + while (errno == EINVAL && (maxblk -= 1024)) { + nread = read(inp, buff, maxblk); + if (nread >= 0) + goto r1; + } + fprintf(stderr, "read error, file %d, record %ld: ", + filen, record); + perror(""); + exit(1); + } else if (nread != lastnread) { + if (lastnread != 0 && lastnread != NOCOUNT) { + if (lastrec == 0 && nread == 0) + fprintf(msg, "%ld records\n", record); + else if (record - lastrec > 1) + fprintf(msg, "records %ld to %ld\n", + lastrec, record); + else + fprintf(msg, "record %ld\n", lastrec); + } + if (nread != 0) + fprintf(msg, "file %d: block size %d: ", + filen, nread); + (void) fflush(stdout); + lastrec = record; + } +r1: guesslen = 0; + if (nread > 0) { + if (op == COPY || op == COPYVERIFY) { + if (needeof) { + writeop(outp, MTWEOF); + needeof = 0; + } + nw = write(outp, buff, nread); + if (nw != nread) { + fprintf(stderr, + "write error, file %d, record %ld: ", + filen, record); + if (nw == -1) + perror(""); + else + fprintf(stderr, + "write (%d) != read (%d)\n", + nw, nread); + fprintf(stderr, "copy aborted\n"); + exit(5); + } + } + size += nread; + record++; + } else { + if (lastnread <= 0 && lastnread != NOCOUNT) { + fprintf(msg, "eot\n"); + break; + } + fprintf(msg, + "file %d: eof after %ld records: %ld bytes\n", + filen, record, size); + needeof = 1; + filen++; + tsize += size; + size = record = lastrec = 0; + lastnread = 0; + } + lastnread = nread; + } + fprintf(msg, "total length: %ld bytes\n", tsize); + (void)signal(SIGINT, oldsig); + if (op == COPY || op == COPYVERIFY) { + writeop(outp, MTWEOF); + writeop(outp, MTWEOF); + if (op == COPYVERIFY) { + writeop(outp, MTREW); + writeop(inp, MTREW); + verify(inp, outp, buff); + } + } + exit(0); +} + +void +verify(inp, outp, outb) + register int inp, outp; + register char *outb; +{ + register int eot, inmaxblk, inn, outmaxblk, outn; + register char *inb; + + inb = getspace(maxblk); + inmaxblk = outmaxblk = maxblk; + for (eot = 0;; guesslen = 0) { + if ((inn = read(inp, inb, inmaxblk)) == -1) { + if (guesslen) + while (errno == EINVAL && (inmaxblk -= 1024)) { + inn = read(inp, inb, inmaxblk); + if (inn >= 0) + goto r1; + } + perror("tcopy: read error"); + break; + } +r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { + if (guesslen) + while (errno == EINVAL && (outmaxblk -= 1024)) { + outn = read(outp, outb, outmaxblk); + if (outn >= 0) + goto r2; + } + perror("tcopy: read error"); + break; + } +r2: if (inn != outn) { + fprintf(msg, + "%s: tapes have different block sizes; %d != %d.\n", + "tcopy", inn, outn); + break; + } + if (!inn) { + if (eot++) { + fprintf(msg, "tcopy: tapes are identical.\n"); + return; + } + } else { + if (bcmp(inb, outb, inn)) { + fprintf(msg, + "tcopy: tapes have different data.\n"); + break; + } + eot = 0; + } + } + exit(1); +} + +void +intr(signo) + int signo; +{ + if (record) + if (record - lastrec > 1) + fprintf(msg, "records %ld to %ld\n", lastrec, record); + else + fprintf(msg, "record %ld\n", lastrec); + fprintf(msg, "interrupt at file %d: record %ld\n", filen, record); + fprintf(msg, "total length: %ld bytes\n", tsize + size); + exit(1); +} + +void * +getspace(blk) + int blk; +{ + void *bp; + + if ((bp = malloc((size_t)blk)) == NULL) { + fprintf(stderr, "tcopy: no memory\n"); + exit(11); + } + return (bp); +} + +void +writeop(fd, type) + int fd, type; +{ + struct mtop op; + + op.mt_op = type; + op.mt_count = (daddr_t)1; + if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) { + perror("tcopy: tape op"); + exit(6); + } +} + +void +usage() +{ + fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n"); + exit(1); +} diff --git a/usr.bin/tee/Makefile b/usr.bin/tee/Makefile new file mode 100644 index 0000000..a713132 --- /dev/null +++ b/usr.bin/tee/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tee + +.include diff --git a/usr.bin/tee/tee.1 b/usr.bin/tee/tee.1 new file mode 100644 index 0000000..2e453cb --- /dev/null +++ b/usr.bin/tee/tee.1 @@ -0,0 +1,88 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)tee.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TEE 1 +.Os +.Sh NAME +.Nm tee +.Nd pipe fitting +.Sh SYNOPSIS +.Nm tee +.Op Fl ai +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm tee +utility copies standard input to standard output, +making a copy in zero or more files. +The output is unbuffered. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl a +Append the output to the files rather than +overwriting them. +.It Fl i +Ignore the +.Dv SIGINT +signal. +.El +.Pp +The following operands are available: +.Bl -tag -width file +.It file +A pathname of an output +.Ar file . +.El +.Pp +The +.Nm tee +utility takes the default action for all signals, +except in the event of the +.Fl i +option. +.Pp +The +.Nm tee +utility exits 0 on success, and >0 if an error occurs. +.Sh STANDARDS +The +.Nm tee +function is expected to be +.Tn POSIX +.St -p1003.2 +compatible. diff --git a/usr.bin/tee/tee.c b/usr.bin/tee/tee.c new file mode 100644 index 0000000..ad1110a --- /dev/null +++ b/usr.bin/tee/tee.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tee.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _list { + struct _list *next; + int fd; + char *name; +} LIST; +LIST *head; + +void add __P((int, char *)); +void err __P((int, const char *, ...)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register LIST *p; + register int n, fd, rval, wval; + register char *bp; + int append, ch, exitval; + char *buf; +#define BSIZE (8 * 1024) + + append = 0; + while ((ch = getopt(argc, argv, "ai")) != EOF) + switch((char)ch) { + case 'a': + append = 1; + break; + case 'i': + (void)signal(SIGINT, SIG_IGN); + break; + case '?': + default: + (void)fprintf(stderr, "usage: tee [-ai] [file ...]\n"); + exit(1); + } + argv += optind; + argc -= optind; + + if ((buf = malloc((u_int)BSIZE)) == NULL) + err(1, "%s", strerror(errno)); + + add(STDOUT_FILENO, "stdout"); + + for (exitval = 0; *argv; ++argv) + if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND : + O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) { + err(0, "%s: %s", *argv, strerror(errno)); + exitval = 1; + } else + add(fd, *argv); + + while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0) + for (p = head; p; p = p->next) { + n = rval; + bp = buf; + do { + if ((wval = write(p->fd, bp, n)) == -1) { + err(0, "%s: %s", + p->name, strerror(errno)); + exitval = 1; + break; + } + bp += wval; + } while (n -= wval); + } + if (rval < 0) + err(1, "read: %s", strerror(errno)); + exit(exitval); +} + +void +add(fd, name) + int fd; + char *name; +{ + LIST *p; + + if ((p = malloc((u_int)sizeof(LIST))) == NULL) + err(1, "%s", strerror(errno)); + p->fd = fd; + p->name = name; + p->next = head; + head = p; +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(int doexit, const char *fmt, ...) +#else +err(doexit, fmt, va_alist) + int doexit; + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "tee: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (doexit) + exit(1); +} diff --git a/usr.bin/telnet/Makefile b/usr.bin/telnet/Makefile new file mode 100644 index 0000000..2e38a28 --- /dev/null +++ b/usr.bin/telnet/Makefile @@ -0,0 +1,73 @@ +# +# 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. +# +# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# + +PROG= telnet + +CFLAGS+=-DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DAUTHENTICATION -DENCRYPTION +CFLAGS+=-DENV_HACK +CFLAGS+=-I${.CURDIR}/../../lib + +CFLAGS+= -DKRB4 + +LDADD= -ltermcap -ltelnet +LDADD+= -lkrb -ldes +DPADD= ${LIBTERMCAP} + +SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c telnet.c \ + terminal.c tn3270.c utilities.c + +# These are the sources that have encryption stuff in them. +CRYPT_SRC= authenc.c commands.c externs.h main.c network.c +CRYPT_SRC+= ring.c ring.h telnet.c terminal.c utilities.c Makefile +NOCRYPT_DIR=${.CURDIR}/Nocrypt + +.include + +nocrypt: +#ifdef ENCRYPTION + @for i in ${CRYPT_SRC}; do \ + if [ ! -d ${NOCRYPT_DIR} ]; then \ + echo Creating subdirectory ${NOCRYPT_DIR}; \ + mkdir ${NOCRYPT_DIR}; \ + fi; \ + echo ${NOCRYPT_DIR}/$$i; \ + unifdef -UENCRYPTION ${.CURDIR}/$$i | \ + sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \ + done + +placeholder: +#else /* ENCRYPTION */ + @echo "Encryption code already removed." +#endif /* ENCRYPTION */ diff --git a/usr.bin/telnet/README b/usr.bin/telnet/README new file mode 100644 index 0000000..086c88f --- /dev/null +++ b/usr.bin/telnet/README @@ -0,0 +1,566 @@ + + +This is a distribution of both client and server telnet. These programs +have been compiled on: + telnet telnetd + BSD 4.3 Reno X X + UNICOS 5.1 X X + UNICOS 6.0 X X + UNICOS 6.1 X X + UNICOS 7.0 X X + SunOs 3.5 X X (no linemode in server) + SunOs 4.1 X X (no linemode in server) + DYNIX V3.0.17.9 X X (no linemode in server) + Ultrix 3.1 X X (no linemode in server) + Ultrix 4.0 X X (no linemode in server) + +In addition, previous versions have been compiled on the following +machines, but were not available for testing this version. + telnet telnetd + SunOs 4.0.3c X X (no linemode in server) + BSD 4.3 X X (no linemode in server) + DYNIX V3.0.12 X X (no linemode in server) + +Februrary 22, 1991: + + Features: + + This version of telnet/telnetd has support for both + the AUTHENTICATION and ENCRYPTION options. The + AUTHENTICATION option is fairly well defined, and + an option number has been assigned to it. The + ENCRYPTION option is still in a state of flux; an + option number has NOT been assigned to it yet. + The code is provided in this release for experimental + and testing purposes. + + The telnet "send" command can now be used to send + do/dont/will/wont commands, with any telnet option + name. The rules for when do/dont/will/wont are sent + are still followed, so just because the user requests + that one of these be sent doesn't mean that it will + be sent... + + The telnet "getstatus" command no longer requires + that option printing be enabled to see the response + to the "DO STATUS" command. + + A -n flag has been added to telnetd to disable + keepalives. + + A new telnet command, "auth" has been added (if + AUTHENTICATE is defined). It has four sub-commands, + "status", "debug", "disable", "enable" and "help". + + A new telnet command, "encrypt" has been added (if + ENCRYPT is defined). It has many sub-commands: + "enable", "type", "start", "stop", "input", + "-input", "output", "-output", "status", "auto", + "verbose", "debug", and "help". + + An "rlogin" interface has been added. If the program + is named "rlogin", or the "-r" flag is given, then + an rlogin type of interface will be used. + ~. Terminates the session + ~ Suspend the session + ~^] Escape to telnet command mode + ~~ Pass through the ~. + BUG: If you type the rlogin escape character + in the middle of a line while in rlogin + mode, you cannot erase it or any characters + before it. Hopefully this can be fixed + in a future release... + + General changes: + + A "libtelnet.a" has now been created. This libraray + contains code that is common to both telnet and + telnetd. This is also where library routines that + are needed, but are not in the standard C library, + are placed. + + The makefiles have been re-done. All of the site + specific configuration information has now been put + into a single "Config.generic" file, in the top level + directory. Changing this one file will take care of + all three subdirectories. Also, to add a new/local + definition, a "Config.local" file may be created + at the top level; if that file exists, the subdirectories + will use that file instead of "Config.generic". + + Many 1-2 line functions in commands.c have been + removed, and just inserted in-line, or replaced + with a macro. + + Bug Fixes: + + The non-termio code in both telnet and telnetd was + setting/clearing CTLECH in the sg_flags word. This + was incorrect, and has been changed to set/clear the + LCTLECH bit in the local mode word. + + The SRCRT #define has been removed. If IP_OPTIONS + and IPPROTO_IP are defined on the system, then the + source route code is automatically enabled. + + The NO_GETTYTAB #define has been removed; there + is a compatability routine that can be built into + libtelnet to achive the same results. + + The server, telnetd, has been switched to use getopt() + for parsing the argument list. + + The code for getting the input/output speeds via + cfgetispeed()/cfgetospeed() was still not quite + right in telnet. Posix says if the ispeed is 0, + then it is really equal to the ospeed. + + The suboption processing code in telnet now has + explicit checks to make sure that we received + the entire suboption (telnetd was already doing this). + + The telnet code for processing the terminal type + could cause a core dump if an existing connection + was closed, and a new connection opened without + exiting telnet. + + Telnetd was doing a TCSADRAIN when setting the new + terminal settings; This is not good, because it means + that the tcsetattr() will hang waiting for output to + drain, and telnetd is the only one that will drain + the output... The fix is to use TCSANOW which does + not wait. + + Telnetd was improperly setting/clearing the ISTRIP + flag in the c_lflag field, it should be using the + c_iflag field. + + When the child process of telnetd was opening the + slave side of the pty, it was re-setting the EXTPROC + bit too early, and some of the other initialization + code was wiping it out. This would cause telnetd + to go out of linemode and into single character mode. + + One instance of leaving linemode in telnetd forgot + to send a WILL ECHO to the client, the net result + would be that the user would see double character + echo. + + If the MODE was being changed several times very + quickly, telnetd could get out of sync with the + state changes and the returning acks; and wind up + being left in the wrong state. + +September 14, 1990: + + Switch the client to use getopt() for parsing the + argument list. The 4.3Reno getopt.c is included for + systems that don't have getopt(). + + Use the posix _POSIX_VDISABLE value for what value + to use when disabling special characters. If this + is undefined, it defaults to 0x3ff. + + For non-termio systems, TIOCSETP was being used to + change the state of the terminal. This causes the + input queue to be flushed, which we don't want. This + is now changed to TIOCSETN. + + Take out the "#ifdef notdef" around the code in the + server that generates a "sync" when the pty oputput + is flushed. The potential problem is that some older + telnet clients may go into an infinate loop when they + receive a "sync", if so, the server can be compiled + with "NO_URGENT" defined. + + Fix the client where it was setting/clearing the OPOST + bit in the c_lflag field, not the c_oflag field. + + Fix the client where it was setting/clearing the ISTRIP + bit in the c_lflag field, not the c_iflag field. (On + 4.3Reno, this is the ECHOPRT bit in the c_lflag field.) + The client also had its interpretation of WILL BINARY + and DO BINARY reversed. + + Fix a bug in client that would cause a core dump when + attempting to remove the last environment variable. + + In the client, there were a few places were switch() + was being passed a character, and if it was a negative + value, it could get sign extended, and not match + the 8 bit case statements. The fix is to and the + switch value with 0xff. + + Add a couple more printoption() calls in the client, I + don't think there are any more places were a telnet + command can be received and not printed out when + "options" is on. + + A new flag has been added to the client, "-a". Currently, + this just causes the USER name to be sent across, in + the future this may be used to signify that automatic + authentication is requested. + + The USER variable is now only sent by the client if + the "-a" or "-l user" options are explicity used, or + if the user explicitly asks for the "USER" environment + variable to be exported. In the server, if it receives + the "USER" environment variable, it won't print out the + banner message, so that only "Password:" will be printed. + This makes the symantics more like rlogin, and should be + more familiar to the user. (People are not used to + getting a banner message, and then getting just a + "Password:" prompt.) + + Re-vamp the code for starting up the child login + process. The code was getting ugly, and it was + hard to tell what was really going on. What we + do now is after the fork(), in the child: + 1) make sure we have no controlling tty + 2) open and initialize the tty + 3) do a setsid()/setpgrp() + 4) makes the tty our controlling tty. + On some systems, #2 makes the tty our controlling + tty, and #4 is a no-op. The parent process does + a gets rid of any controlling tty after the child + is fork()ed. + + Use the strdup() library routine in telnet, instead + of the local savestr() routine. If you don't have + strdup(), you need to define NO_STRDUP. + + Add support for ^T (SIGINFO/VSTATUS), found in the + 4.3Reno distribution. This maps to the AYT character. + You need a 4-line bugfix in the kernel to get this + to work properly: + + > *** tty_pty.c.ORG Tue Sep 11 09:41:53 1990 + > --- tty_pty.c Tue Sep 11 17:48:03 1990 + > *************** + > *** 609,613 **** + > if ((tp->t_lflag&NOFLSH) == 0) + > ttyflush(tp, FREAD|FWRITE); + > ! pgsignal(tp->t_pgrp, *(unsigned int *)data); + > return(0); + > } + > --- 609,616 ---- + > if ((tp->t_lflag&NOFLSH) == 0) + > ttyflush(tp, FREAD|FWRITE); + > ! pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); + > ! if ((*(unsigned int *)data == SIGINFO) && + > ! ((tp->t_lflag&NOKERNINFO) == 0)) + > ! ttyinfo(tp); + > return(0); + > } + + The client is now smarter when setting the telnet escape + character; it only sets it to one of VEOL and VEOL2 if + one of them is undefined, and the other one is not already + defined to the telnet escape character. + + Handle TERMIOS systems that have seperate input and output + line speed settings imbedded in the flags. + + Many other minor bug fixes. + +June 20, 1990: + Re-organize makefiles and source tree. The telnet/Source + directory is now gone, and all the source that was in + telnet/Source is now just in the telnet directory. + + Seperate makefile for each system are now gone. There + are two makefiles, Makefile and Makefile.generic. + The "Makefile" has the definitions for the various + system, and "Makefile.generic" does all the work. + There is a variable called "WHAT" that is used to + specify what to make. For example, in the telnet + directory, you might say: + make 4.4bsd WHAT=clean + to clean out the directory. + + Add support for the ENVIRON and XDISPLOC options. + In order for the server to work, login has to have + the "-p" option to preserve environment variables. + + Add the SOFT_TAB and LIT_ECHO modes in the LINEMODE support. + + Add the "-l user" option to command line and open command + (This is passed through the ENVIRON option). + + Add the "-e" command line option, for setting the escape + character. + + Add the "-D", diagnostic, option to the server. This allows + the server to print out debug information, which is very + useful when trying to debug a telnet that doesn't have any + debugging ability. + + Turn off the literal next character when not in LINEMODE. + + Don't recognize ^Y locally, just pass it through. + + Make minor modifications for Sun4.0 and Sun4.1 + + Add support for both FORW1 and FORW2 characters. The + telnet escpape character is set to whichever of the + two is not being used. If both are in use, the escape + character is not set, so when in linemode the user will + have to follow the escape character with a or + + +The following TELNET options are supported: + + LINEMODE: + The LINEMODE option is supported as per RFC1116. The + FORWARDMASK option is not currently supported. + + BINARY: The client has the ability to turn on/off the BINARY + option in each direction. Turning on BINARY from + server to client causes the LITOUT bit to get set in + the terminal driver on both ends, turning on BINARY + from the client to the server causes the PASS8 bit + to get set in the terminal driver on both ends. + + TERMINAL-TYPE: + This is supported as per RFC1091. On the server side, + when a terminal type is received, termcap/terminfo + is consulted to determine if it is a known terminal + type. It keeps requesting terminal types until it + gets one that it recongnizes, or hits the end of the + list. The server side looks up the entry in the + termcap/terminfo data base, and generates a list of + names which it then passes one at a time to each + request for a terminal type, duplicating the last + entry in the list before cycling back to the beginning. + + NAWS: The Negotiate about Window Size, as per RFC 1073. + + TERMINAL-SPEED: + Implemented as per RFC 1079 + + TOGGLE-FLOW-CONTROL: + Implemented as per RFC 1080 + + TIMING-MARK: + As per RFC 860 + + SGA: As per RFC 858 + + ECHO: As per RFC 857 + + STATUS: + The server will send its current status upon + request. It does not ask for the clients status. + The client will request the servers current status + from the "send getstatus" command. + + ENVIRON: + This option is currently being defined by the IETF + Telnet Working Group, and an RFC has not yet been + issued, but should be in the near future... + + X-DISPLAY-LOCATION: + This functionality can be done through the ENVIRON + option, it is added here for completeness. + + AUTHENTICATION: + This option is currently being defined by the IETF + Telnet Working Group, and an RFC has not yet been + issued. The basic framework is pretty much decided, + but the definitions for the specific authentication + schemes is still in a state of flux. + + ENCRYPT: + This option is currently being defined by the IETF + Telnet Working Group, and an RFC has not yet been + issued. The draft RFC is still in a state of flux, + so this code may change in the future. diff --git a/usr.bin/telnet/authenc.c b/usr.bin/telnet/authenc.c new file mode 100644 index 0000000..545df78 --- /dev/null +++ b/usr.bin/telnet/authenc.c @@ -0,0 +1,111 @@ +/*- + * 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[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#if defined(AUTHENTICATION) || defined(ENCRYPTION) +#include +#include +#include +#include + +#include "general.h" +#include "ring.h" +#include "externs.h" +#include "defines.h" +#include "types.h" + + int +net_write(str, len) + unsigned char *str; + int len; +{ + if (NETROOM() > len) { + ring_supply_data(&netoring, str, len); + if (str[0] == IAC && str[1] == SE) + printsub('>', &str[2], len-2); + return(len); + } + return(0); +} + + void +net_encrypt() +{ +#ifdef ENCRYPTION + if (encrypt_output) + ring_encrypt(&netoring, encrypt_output); + else + ring_clearto(&netoring); +#endif /* ENCRYPTION */ +} + + int +telnet_spin() +{ + return(-1); +} + + char * +telnet_getenv(val) + char *val; +{ + return((char *)env_getvalue((unsigned char *)val)); +} + + char * +telnet_gets(prompt, result, length, echo) + char *prompt; + char *result; + int length; + int echo; +{ + extern char *getpass(); + extern int globalmode; + int om = globalmode; + char *res; + + TerminalNewMode(-1); + if (echo) { + printf("%s", prompt); + res = fgets(result, length, stdin); + } else if (res = getpass(prompt)) { + strncpy(result, res, length); + res = result; + } + TerminalNewMode(om); + return(res); +} +#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ diff --git a/usr.bin/telnet/commands.c b/usr.bin/telnet/commands.c new file mode 100644 index 0000000..a7224d1 --- /dev/null +++ b/usr.bin/telnet/commands.c @@ -0,0 +1,2933 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)commands.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +#if defined(unix) +#include +#if defined(CRAY) || defined(sysV88) +#include +#endif +#include +#else +#include +#endif /* defined(unix) */ +#include +#include +#ifdef CRAY +#include +#endif /* CRAY */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "general.h" + +#include "ring.h" + +#include "externs.h" +#include "defines.h" +#include "types.h" + +#if !defined(CRAY) && !defined(sysV88) +#include +# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix) +# include +# endif /* vax */ +#endif /* !defined(CRAY) && !defined(sysV88) */ +#include + + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif MAXHOSTNAMELEN + +#if defined(IPPROTO_IP) && defined(IP_TOS) +int tos = -1; +#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ + +char *hostname; +static char _hostname[MAXHOSTNAMELEN]; + +extern char *getenv(); + +extern int isprefix(); +extern char **genget(); +extern int Ambiguous(); + +static call(); + +typedef struct { + char *name; /* command name */ + char *help; /* help string (NULL for no help) */ + int (*handler)(); /* routine which executes command */ + int needconnect; /* Do we need to be connected to execute? */ +} Command; + +static char line[256]; +static char saveline[256]; +static int margc; +static char *margv[20]; + + static void +makeargv() +{ + register char *cp, *cp2, c; + register char **argp = margv; + + margc = 0; + cp = line; + if (*cp == '!') { /* Special case shell escape */ + strcpy(saveline, line); /* save for shell command */ + *argp++ = "!"; /* No room in string to get this */ + margc++; + cp++; + } + while (c = *cp) { + register int inquote = 0; + while (isspace(c)) + c = *++cp; + if (c == '\0') + break; + *argp++ = cp; + margc += 1; + for (cp2 = cp; c != '\0'; c = *++cp) { + if (inquote) { + if (c == inquote) { + inquote = 0; + continue; + } + } else { + if (c == '\\') { + if ((c = *++cp) == '\0') + break; + } else if (c == '"') { + inquote = '"'; + continue; + } else if (c == '\'') { + inquote = '\''; + continue; + } else if (isspace(c)) + break; + } + *cp2++ = c; + } + *cp2 = '\0'; + if (c == '\0') + break; + cp++; + } + *argp++ = 0; +} + +/* + * Make a character string into a number. + * + * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). + */ + + static +special(s) + register char *s; +{ + register char c; + char b; + + switch (*s) { + case '^': + b = *++s; + if (b == '?') { + c = b | 0x40; /* DEL */ + } else { + c = b & 0x1f; + } + break; + default: + c = *s; + break; + } + return c; +} + +/* + * Construct a control character sequence + * for a special character. + */ + static char * +control(c) + register cc_t c; +{ + static char buf[5]; + /* + * The only way I could get the Sun 3.5 compiler + * to shut up about + * if ((unsigned int)c >= 0x80) + * was to assign "c" to an unsigned int variable... + * Arggg.... + */ + register unsigned int uic = (unsigned int)c; + + if (uic == 0x7f) + return ("^?"); + if (c == (cc_t)_POSIX_VDISABLE) { + return "off"; + } + if (uic >= 0x80) { + buf[0] = '\\'; + buf[1] = ((c>>6)&07) + '0'; + buf[2] = ((c>>3)&07) + '0'; + buf[3] = (c&07) + '0'; + buf[4] = 0; + } else if (uic >= 0x20) { + buf[0] = c; + buf[1] = 0; + } else { + buf[0] = '^'; + buf[1] = '@'+c; + buf[2] = 0; + } + return (buf); +} + + + +/* + * The following are data structures and routines for + * the "send" command. + * + */ + +struct sendlist { + char *name; /* How user refers to it (case independent) */ + char *help; /* Help information (0 ==> no help) */ + int needconnect; /* Need to be connected */ + int narg; /* Number of arguments */ + int (*handler)(); /* Routine to perform (for special ops) */ + int nbyte; /* Number of bytes to send this command */ + int what; /* Character to be sent (<0 ==> special) */ +}; + + +static int + send_esc P((void)), + send_help P((void)), + send_docmd P((char *)), + send_dontcmd P((char *)), + send_willcmd P((char *)), + send_wontcmd P((char *)); + +static struct sendlist Sendlist[] = { + { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, + { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, + { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, + { "break", 0, 1, 0, 0, 2, BREAK }, + { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, + { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, + { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, + { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, + { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, + { "intp", 0, 1, 0, 0, 2, IP }, + { "interrupt", 0, 1, 0, 0, 2, IP }, + { "intr", 0, 1, 0, 0, 2, IP }, + { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, + { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, + { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, + { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, + { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, + { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, + { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, + { "?", "Display send options", 0, 0, send_help, 0, 0 }, + { "help", 0, 0, 0, send_help, 0, 0 }, + { "do", 0, 0, 1, send_docmd, 3, 0 }, + { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, + { "will", 0, 0, 1, send_willcmd, 3, 0 }, + { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, + { 0 } +}; + +#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ + sizeof(struct sendlist))) + + static int +sendcmd(argc, argv) + int argc; + char **argv; +{ + int count; /* how many bytes we are going to need to send */ + int i; + int question = 0; /* was at least one argument a question */ + struct sendlist *s; /* pointer to current command */ + int success = 0; + int needconnect = 0; + + if (argc < 2) { + printf("need at least one argument for 'send' command\n"); + printf("'send ?' for help\n"); + return 0; + } + /* + * First, validate all the send arguments. + * In addition, we see how much space we are going to need, and + * whether or not we will be doing a "SYNCH" operation (which + * flushes the network queue). + */ + count = 0; + for (i = 1; i < argc; i++) { + s = GETSEND(argv[i]); + if (s == 0) { + printf("Unknown send argument '%s'\n'send ?' for help.\n", + argv[i]); + return 0; + } else if (Ambiguous(s)) { + printf("Ambiguous send argument '%s'\n'send ?' for help.\n", + argv[i]); + return 0; + } + if (i + s->narg >= argc) { + fprintf(stderr, + "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n", + s->narg, s->narg == 1 ? "" : "s", s->name, s->name); + return 0; + } + count += s->nbyte; + if (s->handler == send_help) { + send_help(); + return 0; + } + + i += s->narg; + needconnect += s->needconnect; + } + if (!connected && needconnect) { + printf("?Need to be connected first.\n"); + printf("'send ?' for help\n"); + return 0; + } + /* Now, do we have enough room? */ + if (NETROOM() < count) { + printf("There is not enough room in the buffer TO the network\n"); + printf("to process your request. Nothing will be done.\n"); + printf("('send synch' will throw away most data in the network\n"); + printf("buffer, if this might help.)\n"); + return 0; + } + /* OK, they are all OK, now go through again and actually send */ + count = 0; + for (i = 1; i < argc; i++) { + if ((s = GETSEND(argv[i])) == 0) { + fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); + (void) quit(); + /*NOTREACHED*/ + } + if (s->handler) { + count++; + success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, + (s->narg > 1) ? argv[i+2] : 0); + i += s->narg; + } else { + NET2ADD(IAC, s->what); + printoption("SENT", IAC, s->what); + } + } + return (count == success); +} + + static int +send_esc() +{ + NETADD(escape); + return 1; +} + + static int +send_docmd(name) + char *name; +{ + return(send_tncmd(send_do, "do", name)); +} + + static int +send_dontcmd(name) + char *name; +{ + return(send_tncmd(send_dont, "dont", name)); +} + static int +send_willcmd(name) + char *name; +{ + return(send_tncmd(send_will, "will", name)); +} + static int +send_wontcmd(name) + char *name; +{ + return(send_tncmd(send_wont, "wont", name)); +} + + int +send_tncmd(func, cmd, name) + void (*func)(); + char *cmd, *name; +{ + char **cpp; + extern char *telopts[]; + register int val = 0; + + if (isprefix(name, "help") || isprefix(name, "?")) { + register int col, len; + + printf("Usage: send %s \n", cmd); + printf("\"value\" must be from 0 to 255\n"); + printf("Valid options are:\n\t"); + + col = 8; + for (cpp = telopts; *cpp; cpp++) { + len = strlen(*cpp) + 3; + if (col + len > 65) { + printf("\n\t"); + col = 8; + } + printf(" \"%s\"", *cpp); + col += len; + } + printf("\n"); + return 0; + } + cpp = (char **)genget(name, telopts, sizeof(char *)); + if (Ambiguous(cpp)) { + fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n", + name, cmd); + return 0; + } + if (cpp) { + val = cpp - telopts; + } else { + register char *cp = name; + + while (*cp >= '0' && *cp <= '9') { + val *= 10; + val += *cp - '0'; + cp++; + } + if (*cp != 0) { + fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n", + name, cmd); + return 0; + } else if (val < 0 || val > 255) { + fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n", + name, cmd); + return 0; + } + } + if (!connected) { + printf("?Need to be connected first.\n"); + return 0; + } + (*func)(val, 1); + return 1; +} + + static int +send_help() +{ + struct sendlist *s; /* pointer to current command */ + for (s = Sendlist; s->name; s++) { + if (s->help) + printf("%-15s %s\n", s->name, s->help); + } + return(0); +} + +/* + * The following are the routines and data structures referred + * to by the arguments to the "toggle" command. + */ + + static int +lclchars() +{ + donelclchars = 1; + return 1; +} + + static int +togdebug() +{ +#ifndef NOT43 + if (net > 0 && + (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { + perror("setsockopt (SO_DEBUG)"); + } +#else /* NOT43 */ + if (debug) { + if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + perror("setsockopt (SO_DEBUG)"); + } else + printf("Cannot turn off socket debugging\n"); +#endif /* NOT43 */ + return 1; +} + + + static int +togcrlf() +{ + if (crlf) { + printf("Will send carriage returns as telnet .\n"); + } else { + printf("Will send carriage returns as telnet .\n"); + } + return 1; +} + +int binmode; + + static int +togbinary(val) + int val; +{ + donebinarytoggle = 1; + + if (val >= 0) { + binmode = val; + } else { + if (my_want_state_is_will(TELOPT_BINARY) && + my_want_state_is_do(TELOPT_BINARY)) { + binmode = 1; + } else if (my_want_state_is_wont(TELOPT_BINARY) && + my_want_state_is_dont(TELOPT_BINARY)) { + binmode = 0; + } + val = binmode ? 0 : 1; + } + + if (val == 1) { + if (my_want_state_is_will(TELOPT_BINARY) && + my_want_state_is_do(TELOPT_BINARY)) { + printf("Already operating in binary mode with remote host.\n"); + } else { + printf("Negotiating binary mode with remote host.\n"); + tel_enter_binary(3); + } + } else { + if (my_want_state_is_wont(TELOPT_BINARY) && + my_want_state_is_dont(TELOPT_BINARY)) { + printf("Already in network ascii mode with remote host.\n"); + } else { + printf("Negotiating network ascii mode with remote host.\n"); + tel_leave_binary(3); + } + } + return 1; +} + + static int +togrbinary(val) + int val; +{ + donebinarytoggle = 1; + + if (val == -1) + val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; + + if (val == 1) { + if (my_want_state_is_do(TELOPT_BINARY)) { + printf("Already receiving in binary mode.\n"); + } else { + printf("Negotiating binary mode on input.\n"); + tel_enter_binary(1); + } + } else { + if (my_want_state_is_dont(TELOPT_BINARY)) { + printf("Already receiving in network ascii mode.\n"); + } else { + printf("Negotiating network ascii mode on input.\n"); + tel_leave_binary(1); + } + } + return 1; +} + + static int +togxbinary(val) + int val; +{ + donebinarytoggle = 1; + + if (val == -1) + val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; + + if (val == 1) { + if (my_want_state_is_will(TELOPT_BINARY)) { + printf("Already transmitting in binary mode.\n"); + } else { + printf("Negotiating binary mode on output.\n"); + tel_enter_binary(2); + } + } else { + if (my_want_state_is_wont(TELOPT_BINARY)) { + printf("Already transmitting in network ascii mode.\n"); + } else { + printf("Negotiating network ascii mode on output.\n"); + tel_leave_binary(2); + } + } + return 1; +} + + +static int togglehelp P((void)); +#if defined(AUTHENTICATION) +extern int auth_togdebug P((int)); +#endif +#ifdef ENCRYPTION +extern int EncryptAutoEnc P((int)); +extern int EncryptAutoDec P((int)); +extern int EncryptDebug P((int)); +extern int EncryptVerbose P((int)); +#endif /* ENCRYPTION */ + +struct togglelist { + char *name; /* name of toggle */ + char *help; /* help message */ + int (*handler)(); /* routine to do actual setting */ + int *variable; + char *actionexplanation; +}; + +static struct togglelist Togglelist[] = { + { "autoflush", + "flushing of output when sending interrupt characters", + 0, + &autoflush, + "flush output when sending interrupt characters" }, + { "autosynch", + "automatic sending of interrupt characters in urgent mode", + 0, + &autosynch, + "send interrupt characters in urgent mode" }, +#if defined(AUTHENTICATION) + { "autologin", + "automatic sending of login and/or authentication info", + 0, + &autologin, + "send login name and/or authentication information" }, + { "authdebug", + "Toggle authentication debugging", + auth_togdebug, + 0, + "print authentication debugging information" }, +#endif +#ifdef ENCRYPTION + { "autoencrypt", + "automatic encryption of data stream", + EncryptAutoEnc, + 0, + "automatically encrypt output" }, + { "autodecrypt", + "automatic decryption of data stream", + EncryptAutoDec, + 0, + "automatically decrypt input" }, + { "verbose_encrypt", + "Toggle verbose encryption output", + EncryptVerbose, + 0, + "print verbose encryption output" }, + { "encdebug", + "Toggle encryption debugging", + EncryptDebug, + 0, + "print encryption debugging information" }, +#endif /* ENCRYPTION */ + { "skiprc", + "don't read ~/.telnetrc file", + 0, + &skiprc, + "skip reading of ~/.telnetrc file" }, + { "binary", + "sending and receiving of binary data", + togbinary, + 0, + 0 }, + { "inbinary", + "receiving of binary data", + togrbinary, + 0, + 0 }, + { "outbinary", + "sending of binary data", + togxbinary, + 0, + 0 }, + { "crlf", + "sending carriage returns as telnet ", + togcrlf, + &crlf, + 0 }, + { "crmod", + "mapping of received carriage returns", + 0, + &crmod, + "map carriage return on output" }, + { "localchars", + "local recognition of certain control characters", + lclchars, + &localchars, + "recognize certain control characters" }, + { " ", "", 0 }, /* empty line */ +#if defined(unix) && defined(TN3270) + { "apitrace", + "(debugging) toggle tracing of API transactions", + 0, + &apitrace, + "trace API transactions" }, + { "cursesdata", + "(debugging) toggle printing of hexadecimal curses data", + 0, + &cursesdata, + "print hexadecimal representation of curses data" }, +#endif /* defined(unix) && defined(TN3270) */ + { "debug", + "debugging", + togdebug, + &debug, + "turn on socket level debugging" }, + { "netdata", + "printing of hexadecimal network data (debugging)", + 0, + &netdata, + "print hexadecimal representation of network traffic" }, + { "prettydump", + "output of \"netdata\" to user readable format (debugging)", + 0, + &prettydump, + "print user readable output for \"netdata\"" }, + { "options", + "viewing of options processing (debugging)", + 0, + &showoptions, + "show option processing" }, +#if defined(unix) + { "termdata", + "(debugging) toggle printing of hexadecimal terminal data", + 0, + &termdata, + "print hexadecimal representation of terminal traffic" }, +#endif /* defined(unix) */ + { "?", + 0, + togglehelp }, + { "help", + 0, + togglehelp }, + { 0 } +}; + + static int +togglehelp() +{ + struct togglelist *c; + + for (c = Togglelist; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s toggle %s\n", c->name, c->help); + else + printf("\n"); + } + } + printf("\n"); + printf("%-15s %s\n", "?", "display help information"); + return 0; +} + + static void +settogglehelp(set) + int set; +{ + struct togglelist *c; + + for (c = Togglelist; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", + c->help); + else + printf("\n"); + } + } +} + +#define GETTOGGLE(name) (struct togglelist *) \ + genget(name, (char **) Togglelist, sizeof(struct togglelist)) + + static int +toggle(argc, argv) + int argc; + char *argv[]; +{ + int retval = 1; + char *name; + struct togglelist *c; + + if (argc < 2) { + fprintf(stderr, + "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); + return 0; + } + argc--; + argv++; + while (argc--) { + name = *argv++; + c = GETTOGGLE(name); + if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", + name); + return 0; + } else if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", + name); + return 0; + } else { + if (c->variable) { + *c->variable = !*c->variable; /* invert it */ + if (c->actionexplanation) { + printf("%s %s.\n", *c->variable? "Will" : "Won't", + c->actionexplanation); + } + } + if (c->handler) { + retval &= (*c->handler)(-1); + } + } + } + return retval; +} + +/* + * The following perform the "set" command. + */ + +#ifdef USE_TERMIO +struct termio new_tc = { 0 }; +#endif + +struct setlist { + char *name; /* name */ + char *help; /* help information */ + void (*handler)(); + cc_t *charp; /* where it is located at */ +}; + +static struct setlist Setlist[] = { +#ifdef KLUDGELINEMODE + { "echo", "character to toggle local echoing on/off", 0, &echoc }, +#endif + { "escape", "character to escape back to telnet command mode", 0, &escape }, + { "rlogin", "rlogin escape character", 0, &rlogin }, + { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, + { " ", "" }, + { " ", "The following need 'localchars' to be toggled true", 0, 0 }, + { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp }, + { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, + { "quit", "character to cause an Abort process", 0, termQuitCharp }, + { "eof", "character to cause an EOF ", 0, termEofCharp }, + { " ", "" }, + { " ", "The following are for local editing in linemode", 0, 0 }, + { "erase", "character to use to erase a character", 0, termEraseCharp }, + { "kill", "character to use to erase a line", 0, termKillCharp }, + { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, + { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, + { "reprint", "character to use for line reprint", 0, termRprntCharp }, + { "worderase", "character to use to erase a word", 0, termWerasCharp }, + { "start", "character to use for XON", 0, termStartCharp }, + { "stop", "character to use for XOFF", 0, termStopCharp }, + { "forw1", "alternate end of line character", 0, termForw1Charp }, + { "forw2", "alternate end of line character", 0, termForw2Charp }, + { "ayt", "alternate AYT character", 0, termAytCharp }, + { 0 } +}; + +#if defined(CRAY) && !defined(__STDC__) +/* Work around compiler bug in pcc 4.1.5 */ + void +_setlist_init() +{ +#ifndef KLUDGELINEMODE +#define N 5 +#else +#define N 6 +#endif + Setlist[N+0].charp = &termFlushChar; + Setlist[N+1].charp = &termIntChar; + Setlist[N+2].charp = &termQuitChar; + Setlist[N+3].charp = &termEofChar; + Setlist[N+6].charp = &termEraseChar; + Setlist[N+7].charp = &termKillChar; + Setlist[N+8].charp = &termLiteralNextChar; + Setlist[N+9].charp = &termSuspChar; + Setlist[N+10].charp = &termRprntChar; + Setlist[N+11].charp = &termWerasChar; + Setlist[N+12].charp = &termStartChar; + Setlist[N+13].charp = &termStopChar; + Setlist[N+14].charp = &termForw1Char; + Setlist[N+15].charp = &termForw2Char; + Setlist[N+16].charp = &termAytChar; +#undef N +} +#endif /* defined(CRAY) && !defined(__STDC__) */ + + static struct setlist * +getset(name) + char *name; +{ + return (struct setlist *) + genget(name, (char **) Setlist, sizeof(struct setlist)); +} + + void +set_escape_char(s) + char *s; +{ + if (rlogin != _POSIX_VDISABLE) { + rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; + printf("Telnet rlogin escape character is '%s'.\n", + control(rlogin)); + } else { + escape = (s && *s) ? special(s) : _POSIX_VDISABLE; + printf("Telnet escape character is '%s'.\n", control(escape)); + } +} + + static int +setcmd(argc, argv) + int argc; + char *argv[]; +{ + int value; + struct setlist *ct; + struct togglelist *c; + + if (argc < 2 || argc > 3) { + printf("Format is 'set Name Value'\n'set ?' for help.\n"); + return 0; + } + if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { + for (ct = Setlist; ct->name; ct++) + printf("%-15s %s\n", ct->name, ct->help); + printf("\n"); + settogglehelp(1); + printf("%-15s %s\n", "?", "display help information"); + return 0; + } + + ct = getset(argv[1]); + if (ct == 0) { + c = GETTOGGLE(argv[1]); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", + argv[1]); + return 0; + } else if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", + argv[1]); + return 0; + } + if (c->variable) { + if ((argc == 2) || (strcmp("on", argv[2]) == 0)) + *c->variable = 1; + else if (strcmp("off", argv[2]) == 0) + *c->variable = 0; + else { + printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); + return 0; + } + if (c->actionexplanation) { + printf("%s %s.\n", *c->variable? "Will" : "Won't", + c->actionexplanation); + } + } + if (c->handler) + (*c->handler)(1); + } else if (argc != 3) { + printf("Format is 'set Name Value'\n'set ?' for help.\n"); + return 0; + } else if (Ambiguous(ct)) { + fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", + argv[1]); + return 0; + } else if (ct->handler) { + (*ct->handler)(argv[2]); + printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp); + } else { + if (strcmp("off", argv[2])) { + value = special(argv[2]); + } else { + value = _POSIX_VDISABLE; + } + *(ct->charp) = (cc_t)value; + printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); + } + slc_check(); + return 1; +} + + static int +unsetcmd(argc, argv) + int argc; + char *argv[]; +{ + struct setlist *ct; + struct togglelist *c; + register char *name; + + if (argc < 2) { + fprintf(stderr, + "Need an argument to 'unset' command. 'unset ?' for help.\n"); + return 0; + } + if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { + for (ct = Setlist; ct->name; ct++) + printf("%-15s %s\n", ct->name, ct->help); + printf("\n"); + settogglehelp(0); + printf("%-15s %s\n", "?", "display help information"); + return 0; + } + + argc--; + argv++; + while (argc--) { + name = *argv++; + ct = getset(name); + if (ct == 0) { + c = GETTOGGLE(name); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", + name); + return 0; + } else if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", + name); + return 0; + } + if (c->variable) { + *c->variable = 0; + if (c->actionexplanation) { + printf("%s %s.\n", *c->variable? "Will" : "Won't", + c->actionexplanation); + } + } + if (c->handler) + (*c->handler)(0); + } else if (Ambiguous(ct)) { + fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", + name); + return 0; + } else if (ct->handler) { + (*ct->handler)(0); + printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp); + } else { + *(ct->charp) = _POSIX_VDISABLE; + printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); + } + } + return 1; +} + +/* + * The following are the data structures and routines for the + * 'mode' command. + */ +#ifdef KLUDGELINEMODE +extern int kludgelinemode; + + static int +dokludgemode() +{ + kludgelinemode = 1; + send_wont(TELOPT_LINEMODE, 1); + send_dont(TELOPT_SGA, 1); + send_dont(TELOPT_ECHO, 1); +} +#endif + + static int +dolinemode() +{ +#ifdef KLUDGELINEMODE + if (kludgelinemode) + send_dont(TELOPT_SGA, 1); +#endif + send_will(TELOPT_LINEMODE, 1); + send_dont(TELOPT_ECHO, 1); + return 1; +} + + static int +docharmode() +{ +#ifdef KLUDGELINEMODE + if (kludgelinemode) + send_do(TELOPT_SGA, 1); + else +#endif + send_wont(TELOPT_LINEMODE, 1); + send_do(TELOPT_ECHO, 1); + return 1; +} + + static int +dolmmode(bit, on) + int bit, on; +{ + unsigned char c; + extern int linemode; + + if (my_want_state_is_wont(TELOPT_LINEMODE)) { + printf("?Need to have LINEMODE option enabled first.\n"); + printf("'mode ?' for help.\n"); + return 0; + } + + if (on) + c = (linemode | bit); + else + c = (linemode & ~bit); + lm_mode(&c, 1, 1); + return 1; +} + + int +setmode(bit) +{ + return dolmmode(bit, 1); +} + + int +clearmode(bit) +{ + return dolmmode(bit, 0); +} + +struct modelist { + char *name; /* command name */ + char *help; /* help string */ + int (*handler)(); /* routine which executes command */ + int needconnect; /* Do we need to be connected to execute? */ + int arg1; +}; + +extern int modehelp(); + +static struct modelist ModeList[] = { + { "character", "Disable LINEMODE option", docharmode, 1 }, +#ifdef KLUDGELINEMODE + { "", "(or disable obsolete line-by-line mode)", 0 }, +#endif + { "line", "Enable LINEMODE option", dolinemode, 1 }, +#ifdef KLUDGELINEMODE + { "", "(or enable obsolete line-by-line mode)", 0 }, +#endif + { "", "", 0 }, + { "", "These require the LINEMODE option to be enabled", 0 }, + { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, + { "+isig", 0, setmode, 1, MODE_TRAPSIG }, + { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, + { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, + { "+edit", 0, setmode, 1, MODE_EDIT }, + { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, + { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, + { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, + { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB }, + { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO }, + { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, + { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO }, + { "help", 0, modehelp, 0 }, +#ifdef KLUDGELINEMODE + { "kludgeline", 0, dokludgemode, 1 }, +#endif + { "", "", 0 }, + { "?", "Print help information", modehelp, 0 }, + { 0 }, +}; + + + int +modehelp() +{ + struct modelist *mt; + + printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); + for (mt = ModeList; mt->name; mt++) { + if (mt->help) { + if (*mt->help) + printf("%-15s %s\n", mt->name, mt->help); + else + printf("\n"); + } + } + return 0; +} + +#define GETMODECMD(name) (struct modelist *) \ + genget(name, (char **) ModeList, sizeof(struct modelist)) + + static int +modecmd(argc, argv) + int argc; + char *argv[]; +{ + struct modelist *mt; + + if (argc != 2) { + printf("'mode' command requires an argument\n"); + printf("'mode ?' for help.\n"); + } else if ((mt = GETMODECMD(argv[1])) == 0) { + fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); + } else if (Ambiguous(mt)) { + fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); + } else if (mt->needconnect && !connected) { + printf("?Need to be connected first.\n"); + printf("'mode ?' for help.\n"); + } else if (mt->handler) { + return (*mt->handler)(mt->arg1); + } + return 0; +} + +/* + * The following data structures and routines implement the + * "display" command. + */ + + static int +display(argc, argv) + int argc; + char *argv[]; +{ + struct togglelist *tl; + struct setlist *sl; + +#define dotog(tl) if (tl->variable && tl->actionexplanation) { \ + if (*tl->variable) { \ + printf("will"); \ + } else { \ + printf("won't"); \ + } \ + printf(" %s.\n", tl->actionexplanation); \ + } + +#define doset(sl) if (sl->name && *sl->name != ' ') { \ + if (sl->handler == 0) \ + printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ + else \ + printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \ + } + + if (argc == 1) { + for (tl = Togglelist; tl->name; tl++) { + dotog(tl); + } + printf("\n"); + for (sl = Setlist; sl->name; sl++) { + doset(sl); + } + } else { + int i; + + for (i = 1; i < argc; i++) { + sl = getset(argv[i]); + tl = GETTOGGLE(argv[i]); + if (Ambiguous(sl) || Ambiguous(tl)) { + printf("?Ambiguous argument '%s'.\n", argv[i]); + return 0; + } else if (!sl && !tl) { + printf("?Unknown argument '%s'.\n", argv[i]); + return 0; + } else { + if (tl) { + dotog(tl); + } + if (sl) { + doset(sl); + } + } + } + } +/*@*/optionstatus(); +#ifdef ENCRYPTION + EncryptStatus(); +#endif /* ENCRYPTION */ + return 1; +#undef doset +#undef dotog +} + +/* + * The following are the data structures, and many of the routines, + * relating to command processing. + */ + +/* + * Set the escape character. + */ + static int +setescape(argc, argv) + int argc; + char *argv[]; +{ + register char *arg; + char buf[50]; + + printf( + "Deprecated usage - please use 'set escape%s%s' in the future.\n", + (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); + if (argc > 2) + arg = argv[1]; + else { + printf("new escape character: "); + (void) fgets(buf, sizeof(buf), stdin); + arg = buf; + } + if (arg[0] != '\0') + escape = arg[0]; + if (!In3270) { + printf("Escape character is '%s'.\n", control(escape)); + } + (void) fflush(stdout); + return 1; +} + + /*VARARGS*/ + static int +togcrmod() +{ + crmod = !crmod; + printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); + printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); + (void) fflush(stdout); + return 1; +} + + /*VARARGS*/ + int +suspend() +{ +#ifdef SIGTSTP + setcommandmode(); + { + long oldrows, oldcols, newrows, newcols, err; + + err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; + (void) kill(0, SIGTSTP); + /* + * If we didn't get the window size before the SUSPEND, but we + * can get them now (???), then send the NAWS to make sure that + * we are set up for the right window size. + */ + if (TerminalWindowSize(&newrows, &newcols) && connected && + (err || ((oldrows != newrows) || (oldcols != newcols)))) { + sendnaws(); + } + } + /* reget parameters in case they were changed */ + TerminalSaveState(); + setconnmode(0); +#else + printf("Suspend is not supported. Try the '!' command instead\n"); +#endif + return 1; +} + +#if !defined(TN3270) + /*ARGSUSED*/ + int +shell(argc, argv) + int argc; + char *argv[]; +{ + long oldrows, oldcols, newrows, newcols, err; + + setcommandmode(); + + err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; + switch(vfork()) { + case -1: + perror("Fork failed\n"); + break; + + case 0: + { + /* + * Fire up the shell in the child. + */ + register char *shellp, *shellname; + extern char *rindex(); + + shellp = getenv("SHELL"); + if (shellp == NULL) + shellp = "/bin/sh"; + if ((shellname = rindex(shellp, '/')) == 0) + shellname = shellp; + else + shellname++; + if (argc > 1) + execl(shellp, shellname, "-c", &saveline[1], 0); + else + execl(shellp, shellname, 0); + perror("Execl"); + _exit(1); + } + default: + (void)wait((int *)0); /* Wait for the shell to complete */ + + if (TerminalWindowSize(&newrows, &newcols) && connected && + (err || ((oldrows != newrows) || (oldcols != newcols)))) { + sendnaws(); + } + break; + } + return 1; +} +#else /* !defined(TN3270) */ +extern int shell(); +#endif /* !defined(TN3270) */ + + /*VARARGS*/ + static +bye(argc, argv) + int argc; /* Number of arguments */ + char *argv[]; /* arguments */ +{ + extern int resettermname; + + if (connected) { + (void) shutdown(net, 2); + printf("Connection closed.\n"); + (void) NetClose(net); + connected = 0; + resettermname = 1; +#if defined(AUTHENTICATION) || defined(ENCRYPTION) + auth_encrypt_connect(connected); +#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ + /* reset options */ + tninit(); +#if defined(TN3270) + SetIn3270(); /* Get out of 3270 mode */ +#endif /* defined(TN3270) */ + } + if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { + longjmp(toplevel, 1); + /* NOTREACHED */ + } + return 1; /* Keep lint, etc., happy */ +} + +/*VARARGS*/ +quit() +{ + (void) call(bye, "bye", "fromquit", 0); + Exit(0); + /*NOTREACHED*/ +} + +/*VARARGS*/ + int +logout() +{ + send_do(TELOPT_LOGOUT, 1); + (void) netflush(); + return 1; +} + + +/* + * The SLC command. + */ + +struct slclist { + char *name; + char *help; + void (*handler)(); + int arg; +}; + +static void slc_help(); + +struct slclist SlcList[] = { + { "export", "Use local special character definitions", + slc_mode_export, 0 }, + { "import", "Use remote special character definitions", + slc_mode_import, 1 }, + { "check", "Verify remote special character definitions", + slc_mode_import, 0 }, + { "help", 0, slc_help, 0 }, + { "?", "Print help information", slc_help, 0 }, + { 0 }, +}; + + static void +slc_help() +{ + struct slclist *c; + + for (c = SlcList; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s %s\n", c->name, c->help); + else + printf("\n"); + } + } +} + + static struct slclist * +getslc(name) + char *name; +{ + return (struct slclist *) + genget(name, (char **) SlcList, sizeof(struct slclist)); +} + + static +slccmd(argc, argv) + int argc; + char *argv[]; +{ + struct slclist *c; + + if (argc != 2) { + fprintf(stderr, + "Need an argument to 'slc' command. 'slc ?' for help.\n"); + return 0; + } + c = getslc(argv[1]); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", + argv[1]); + return 0; + } + if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", + argv[1]); + return 0; + } + (*c->handler)(c->arg); + slcstate(); + return 1; +} + +/* + * The ENVIRON command. + */ + +struct envlist { + char *name; + char *help; + void (*handler)(); + int narg; +}; + +extern struct env_lst * + env_define P((unsigned char *, unsigned char *)); +extern void + env_undefine P((unsigned char *)), + env_export P((unsigned char *)), + env_unexport P((unsigned char *)), + env_send P((unsigned char *)), +#if defined(OLD_ENVIRON) && defined(ENV_HACK) + env_varval P((unsigned char *)), +#endif + env_list P((void)); +static void + env_help P((void)); + +struct envlist EnvList[] = { + { "define", "Define an environment variable", + (void (*)())env_define, 2 }, + { "undefine", "Undefine an environment variable", + env_undefine, 1 }, + { "export", "Mark an environment variable for automatic export", + env_export, 1 }, + { "unexport", "Don't mark an environment variable for automatic export", + env_unexport, 1 }, + { "send", "Send an environment variable", env_send, 1 }, + { "list", "List the current environment variables", + env_list, 0 }, +#if defined(OLD_ENVIRON) && defined(ENV_HACK) + { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", + env_varval, 1 }, +#endif + { "help", 0, env_help, 0 }, + { "?", "Print help information", env_help, 0 }, + { 0 }, +}; + + static void +env_help() +{ + struct envlist *c; + + for (c = EnvList; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s %s\n", c->name, c->help); + else + printf("\n"); + } + } +} + + static struct envlist * +getenvcmd(name) + char *name; +{ + return (struct envlist *) + genget(name, (char **) EnvList, sizeof(struct envlist)); +} + +env_cmd(argc, argv) + int argc; + char *argv[]; +{ + struct envlist *c; + + if (argc < 2) { + fprintf(stderr, + "Need an argument to 'environ' command. 'environ ?' for help.\n"); + return 0; + } + c = getenvcmd(argv[1]); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n", + argv[1]); + return 0; + } + if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", + argv[1]); + return 0; + } + if (c->narg + 2 != argc) { + fprintf(stderr, + "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n", + c->narg < argc + 2 ? "only " : "", + c->narg, c->narg == 1 ? "" : "s", c->name); + return 0; + } + (*c->handler)(argv[2], argv[3]); + return 1; +} + +struct env_lst { + struct env_lst *next; /* pointer to next structure */ + struct env_lst *prev; /* pointer to previous structure */ + unsigned char *var; /* pointer to variable name */ + unsigned char *value; /* pointer to variable value */ + int export; /* 1 -> export with default list of variables */ + int welldefined; /* A well defined variable */ +}; + +struct env_lst envlisthead; + + struct env_lst * +env_find(var) + unsigned char *var; +{ + register struct env_lst *ep; + + for (ep = envlisthead.next; ep; ep = ep->next) { + if (strcmp((char *)ep->var, (char *)var) == 0) + return(ep); + } + return(NULL); +} + + void +env_init() +{ + extern char **environ; + register char **epp, *cp; + register struct env_lst *ep; + extern char *index(); + + for (epp = environ; *epp; epp++) { + if (cp = index(*epp, '=')) { + *cp = '\0'; + ep = env_define((unsigned char *)*epp, + (unsigned char *)cp+1); + ep->export = 0; + *cp = '='; + } + } + /* + * Special case for DISPLAY variable. If it is ":0.0" or + * "unix:0.0", we have to get rid of "unix" and insert our + * hostname. + */ + if ((ep = env_find("DISPLAY")) + && ((*ep->value == ':') + || (strncmp((char *)ep->value, "unix:", 5) == 0))) { + char hbuf[256+1]; + char *cp2 = index((char *)ep->value, ':'); + + gethostname(hbuf, 256); + hbuf[256] = '\0'; + cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1); + sprintf((char *)cp, "%s%s", hbuf, cp2); + free(ep->value); + ep->value = (unsigned char *)cp; + } + /* + * If USER is not defined, but LOGNAME is, then add + * USER with the value from LOGNAME. By default, we + * don't export the USER variable. + */ + if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { + env_define((unsigned char *)"USER", ep->value); + env_unexport((unsigned char *)"USER"); + } + env_export((unsigned char *)"DISPLAY"); + env_export((unsigned char *)"PRINTER"); +} + + struct env_lst * +env_define(var, value) + unsigned char *var, *value; +{ + register struct env_lst *ep; + + if (ep = env_find(var)) { + if (ep->var) + free(ep->var); + if (ep->value) + free(ep->value); + } else { + ep = (struct env_lst *)malloc(sizeof(struct env_lst)); + ep->next = envlisthead.next; + envlisthead.next = ep; + ep->prev = &envlisthead; + if (ep->next) + ep->next->prev = ep; + } + ep->welldefined = opt_welldefined(var); + ep->export = 1; + ep->var = (unsigned char *)strdup((char *)var); + ep->value = (unsigned char *)strdup((char *)value); + return(ep); +} + + void +env_undefine(var) + unsigned char *var; +{ + register struct env_lst *ep; + + if (ep = env_find(var)) { + ep->prev->next = ep->next; + if (ep->next) + ep->next->prev = ep->prev; + if (ep->var) + free(ep->var); + if (ep->value) + free(ep->value); + free(ep); + } +} + + void +env_export(var) + unsigned char *var; +{ + register struct env_lst *ep; + + if (ep = env_find(var)) + ep->export = 1; +} + + void +env_unexport(var) + unsigned char *var; +{ + register struct env_lst *ep; + + if (ep = env_find(var)) + ep->export = 0; +} + + void +env_send(var) + unsigned char *var; +{ + register struct env_lst *ep; + + if (my_state_is_wont(TELOPT_NEW_ENVIRON) +#ifdef OLD_ENVIRON + && my_state_is_wont(TELOPT_OLD_ENVIRON) +#endif + ) { + fprintf(stderr, + "Cannot send '%s': Telnet ENVIRON option not enabled\n", + var); + return; + } + ep = env_find(var); + if (ep == 0) { + fprintf(stderr, "Cannot send '%s': variable not defined\n", + var); + return; + } + env_opt_start_info(); + env_opt_add(ep->var); + env_opt_end(0); +} + + void +env_list() +{ + register struct env_lst *ep; + + for (ep = envlisthead.next; ep; ep = ep->next) { + printf("%c %-20s %s\n", ep->export ? '*' : ' ', + ep->var, ep->value); + } +} + + unsigned char * +env_default(init, welldefined) + int init; +{ + static struct env_lst *nep = NULL; + + if (init) { + nep = &envlisthead; + return; + } + if (nep) { + while (nep = nep->next) { + if (nep->export && (nep->welldefined == welldefined)) + return(nep->var); + } + } + return(NULL); +} + + unsigned char * +env_getvalue(var) + unsigned char *var; +{ + register struct env_lst *ep; + + if (ep = env_find(var)) + return(ep->value); + return(NULL); +} + +#if defined(OLD_ENVIRON) && defined(ENV_HACK) + void +env_varval(what) + unsigned char *what; +{ + extern int old_env_var, old_env_value, env_auto; + int len = strlen((char *)what); + + if (len == 0) + goto unknown; + + if (strncasecmp((char *)what, "status", len) == 0) { + if (env_auto) + printf("%s%s", "VAR and VALUE are/will be ", + "determined automatically\n"); + if (old_env_var == OLD_ENV_VAR) + printf("VAR and VALUE set to correct definitions\n"); + else + printf("VAR and VALUE definitions are reversed\n"); + } else if (strncasecmp((char *)what, "auto", len) == 0) { + env_auto = 1; + old_env_var = OLD_ENV_VALUE; + old_env_value = OLD_ENV_VAR; + } else if (strncasecmp((char *)what, "right", len) == 0) { + env_auto = 0; + old_env_var = OLD_ENV_VAR; + old_env_value = OLD_ENV_VALUE; + } else if (strncasecmp((char *)what, "wrong", len) == 0) { + env_auto = 0; + old_env_var = OLD_ENV_VALUE; + old_env_value = OLD_ENV_VAR; + } else { +unknown: + printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n"); + } +} +#endif + +#if defined(AUTHENTICATION) +/* + * The AUTHENTICATE command. + */ + +struct authlist { + char *name; + char *help; + int (*handler)(); + int narg; +}; + +extern int + auth_enable P((int)), + auth_disable P((int)), + auth_status P((void)); +static int + auth_help P((void)); + +struct authlist AuthList[] = { + { "status", "Display current status of authentication information", + auth_status, 0 }, + { "disable", "Disable an authentication type ('auth disable ?' for more)", + auth_disable, 1 }, + { "enable", "Enable an authentication type ('auth enable ?' for more)", + auth_enable, 1 }, + { "help", 0, auth_help, 0 }, + { "?", "Print help information", auth_help, 0 }, + { 0 }, +}; + + static int +auth_help() +{ + struct authlist *c; + + for (c = AuthList; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s %s\n", c->name, c->help); + else + printf("\n"); + } + } + return 0; +} + +auth_cmd(argc, argv) + int argc; + char *argv[]; +{ + struct authlist *c; + + c = (struct authlist *) + genget(argv[1], (char **) AuthList, sizeof(struct authlist)); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n", + argv[1]); + return 0; + } + if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n", + argv[1]); + return 0; + } + if (c->narg + 2 != argc) { + fprintf(stderr, + "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n", + c->narg < argc + 2 ? "only " : "", + c->narg, c->narg == 1 ? "" : "s", c->name); + return 0; + } + return((*c->handler)(argv[2], argv[3])); +} +#endif + +#ifdef ENCRYPTION +/* + * The ENCRYPT command. + */ + +struct encryptlist { + char *name; + char *help; + int (*handler)(); + int needconnect; + int minarg; + int maxarg; +}; + +extern int + EncryptEnable P((char *, char *)), + EncryptDisable P((char *, char *)), + EncryptType P((char *, char *)), + EncryptStart P((char *)), + EncryptStartInput P((void)), + EncryptStartOutput P((void)), + EncryptStop P((char *)), + EncryptStopInput P((void)), + EncryptStopOutput P((void)), + EncryptStatus P((void)); +static int + EncryptHelp P((void)); + +struct encryptlist EncryptList[] = { + { "enable", "Enable encryption. ('encrypt enable ?' for more)", + EncryptEnable, 1, 1, 2 }, + { "disable", "Disable encryption. ('encrypt enable ?' for more)", + EncryptDisable, 0, 1, 2 }, + { "type", "Set encryptiong type. ('encrypt type ?' for more)", + EncryptType, 0, 1, 1 }, + { "start", "Start encryption. ('encrypt start ?' for more)", + EncryptStart, 1, 0, 1 }, + { "stop", "Stop encryption. ('encrypt stop ?' for more)", + EncryptStop, 1, 0, 1 }, + { "input", "Start encrypting the input stream", + EncryptStartInput, 1, 0, 0 }, + { "-input", "Stop encrypting the input stream", + EncryptStopInput, 1, 0, 0 }, + { "output", "Start encrypting the output stream", + EncryptStartOutput, 1, 0, 0 }, + { "-output", "Stop encrypting the output stream", + EncryptStopOutput, 1, 0, 0 }, + + { "status", "Display current status of authentication information", + EncryptStatus, 0, 0, 0 }, + { "help", 0, EncryptHelp, 0, 0, 0 }, + { "?", "Print help information", EncryptHelp, 0, 0, 0 }, + { 0 }, +}; + + static int +EncryptHelp() +{ + struct encryptlist *c; + + for (c = EncryptList; c->name; c++) { + if (c->help) { + if (*c->help) + printf("%-15s %s\n", c->name, c->help); + else + printf("\n"); + } + } + return 0; +} + +encrypt_cmd(argc, argv) + int argc; + char *argv[]; +{ + struct encryptlist *c; + + c = (struct encryptlist *) + genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); + if (c == 0) { + fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n", + argv[1]); + return 0; + } + if (Ambiguous(c)) { + fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n", + argv[1]); + return 0; + } + argc -= 2; + if (argc < c->minarg || argc > c->maxarg) { + if (c->minarg == c->maxarg) { + fprintf(stderr, "Need %s%d argument%s ", + c->minarg < argc ? "only " : "", c->minarg, + c->minarg == 1 ? "" : "s"); + } else { + fprintf(stderr, "Need %s%d-%d arguments ", + c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); + } + fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n", + c->name); + return 0; + } + if (c->needconnect && !connected) { + if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { + printf("?Need to be connected first.\n"); + return 0; + } + } + return ((*c->handler)(argc > 0 ? argv[2] : 0, + argc > 1 ? argv[3] : 0, + argc > 2 ? argv[4] : 0)); +} +#endif /* ENCRYPTION */ + +#if defined(unix) && defined(TN3270) + static void +filestuff(fd) + int fd; +{ + int res; + +#ifdef F_GETOWN + setconnmode(0); + res = fcntl(fd, F_GETOWN, 0); + setcommandmode(); + + if (res == -1) { + perror("fcntl"); + return; + } + printf("\tOwner is %d.\n", res); +#endif + + setconnmode(0); + res = fcntl(fd, F_GETFL, 0); + setcommandmode(); + + if (res == -1) { + perror("fcntl"); + return; + } +#ifdef notdef + printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); +#endif +} +#endif /* defined(unix) && defined(TN3270) */ + +/* + * Print status about the connection. + */ + /*ARGSUSED*/ + static +status(argc, argv) + int argc; + char *argv[]; +{ + if (connected) { + printf("Connected to %s.\n", hostname); + if ((argc < 2) || strcmp(argv[1], "notmuch")) { + int mode = getconnmode(); + + if (my_want_state_is_will(TELOPT_LINEMODE)) { + printf("Operating with LINEMODE option\n"); + printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); + printf("%s catching of signals\n", + (mode&MODE_TRAPSIG) ? "Local" : "No"); + slcstate(); +#ifdef KLUDGELINEMODE + } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { + printf("Operating in obsolete linemode\n"); +#endif + } else { + printf("Operating in single character mode\n"); + if (localchars) + printf("Catching signals locally\n"); + } + printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); + if (my_want_state_is_will(TELOPT_LFLOW)) + printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); +#ifdef ENCRYPTION + encrypt_display(); +#endif /* ENCRYPTION */ + } + } else { + printf("No connection.\n"); + } +# if !defined(TN3270) + printf("Escape character is '%s'.\n", control(escape)); + (void) fflush(stdout); +# else /* !defined(TN3270) */ + if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { + printf("Escape character is '%s'.\n", control(escape)); + } +# if defined(unix) + if ((argc >= 2) && !strcmp(argv[1], "everything")) { + printf("SIGIO received %d time%s.\n", + sigiocount, (sigiocount == 1)? "":"s"); + if (In3270) { + printf("Process ID %d, process group %d.\n", + getpid(), getpgrp(getpid())); + printf("Terminal input:\n"); + filestuff(tin); + printf("Terminal output:\n"); + filestuff(tout); + printf("Network socket:\n"); + filestuff(net); + } + } + if (In3270 && transcom) { + printf("Transparent mode command is '%s'.\n", transcom); + } +# endif /* defined(unix) */ + (void) fflush(stdout); + if (In3270) { + return 0; + } +# endif /* defined(TN3270) */ + return 1; +} + +#ifdef SIGINFO +/* + * Function that gets called when SIGINFO is received. + */ +ayt_status() +{ + (void) call(status, "status", "notmuch", 0); +} +#endif + +unsigned long inet_addr(); + + int +tn(argc, argv) + int argc; + char *argv[]; +{ + register struct hostent *host = 0; + struct sockaddr_in sin; + struct servent *sp = 0; + unsigned long temp; + extern char *inet_ntoa(); +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) + char *srp = 0, *strrchr(); + unsigned long sourceroute(), srlen; +#endif + char *cmd, *hostp = 0, *portp = 0, *user = 0; + + /* clear the socket address prior to use */ + bzero((char *)&sin, sizeof(sin)); + + if (connected) { + printf("?Already connected to %s\n", hostname); + setuid(getuid()); + return 0; + } + if (argc < 2) { + (void) strcpy(line, "open "); + printf("(to) "); + (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); + makeargv(); + argc = margc; + argv = margv; + } + cmd = *argv; + --argc; ++argv; + while (argc) { + if (isprefix(*argv, "help") || isprefix(*argv, "?")) + goto usage; + if (strcmp(*argv, "-l") == 0) { + --argc; ++argv; + if (argc == 0) + goto usage; + user = *argv++; + --argc; + continue; + } + if (strcmp(*argv, "-a") == 0) { + --argc; ++argv; + autologin = 1; + continue; + } + if (hostp == 0) { + hostp = *argv++; + --argc; + continue; + } + if (portp == 0) { + portp = *argv++; + --argc; + continue; + } + usage: + printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); + setuid(getuid()); + return 0; + } + if (hostp == 0) + goto usage; + +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) + if (hostp[0] == '@' || hostp[0] == '!') { + if ((hostname = strrchr(hostp, ':')) == NULL) + hostname = strrchr(hostp, '@'); + hostname++; + srp = 0; + temp = sourceroute(hostp, &srp, &srlen); + if (temp == 0) { + herror(srp); + setuid(getuid()); + return 0; + } else if (temp == -1) { + printf("Bad source route option: %s\n", hostp); + setuid(getuid()); + return 0; + } else { + sin.sin_addr.s_addr = temp; + sin.sin_family = AF_INET; + } + } else { +#endif + temp = inet_addr(hostp); + if (temp != (unsigned long) -1) { + sin.sin_addr.s_addr = temp; + sin.sin_family = AF_INET; + (void) strcpy(_hostname, hostp); + hostname = _hostname; + } else { + host = gethostbyname(hostp); + if (host) { + sin.sin_family = host->h_addrtype; +#if defined(h_addr) /* In 4.3, this is a #define */ + memcpy((caddr_t)&sin.sin_addr, + host->h_addr_list[0], host->h_length); +#else /* defined(h_addr) */ + memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); +#endif /* defined(h_addr) */ + strncpy(_hostname, host->h_name, sizeof(_hostname)); + _hostname[sizeof(_hostname)-1] = '\0'; + hostname = _hostname; + } else { + herror(hostp); + setuid(getuid()); + return 0; + } + } +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) + } +#endif + if (portp) { + if (*portp == '-') { + portp++; + telnetport = 1; + } else + telnetport = 0; + sin.sin_port = atoi(portp); + if (sin.sin_port == 0) { + sp = getservbyname(portp, "tcp"); + if (sp) + sin.sin_port = sp->s_port; + else { + printf("%s: bad port number\n", portp); + setuid(getuid()); + return 0; + } + } else { +#if !defined(htons) + u_short htons P((unsigned short)); +#endif /* !defined(htons) */ + sin.sin_port = htons(sin.sin_port); + } + } else { + if (sp == 0) { + sp = getservbyname("telnet", "tcp"); + if (sp == 0) { + fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); + setuid(getuid()); + return 0; + } + sin.sin_port = sp->s_port; + } + telnetport = 1; + } + printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); + do { + net = socket(AF_INET, SOCK_STREAM, 0); + setuid(getuid()); + if (net < 0) { + perror("telnet: socket"); + return 0; + } +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) + if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) + perror("setsockopt (IP_OPTIONS)"); +#endif +#if defined(IPPROTO_IP) && defined(IP_TOS) + { +# if defined(HAS_GETTOS) + struct tosent *tp; + if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) + tos = tp->t_tos; +# endif + if (tos < 0) + tos = 020; /* Low Delay bit */ + if (tos + && (setsockopt(net, IPPROTO_IP, IP_TOS, + (char *)&tos, sizeof(int)) < 0) + && (errno != ENOPROTOOPT)) + perror("telnet: setsockopt (IP_TOS) (ignored)"); + } +#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ + + if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { + perror("setsockopt (SO_DEBUG)"); + } + + if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { +#if defined(h_addr) /* In 4.3, this is a #define */ + if (host && host->h_addr_list[1]) { + int oerrno = errno; + + fprintf(stderr, "telnet: connect to address %s: ", + inet_ntoa(sin.sin_addr)); + errno = oerrno; + perror((char *)0); + host->h_addr_list++; + memcpy((caddr_t)&sin.sin_addr, + host->h_addr_list[0], host->h_length); + (void) NetClose(net); + continue; + } +#endif /* defined(h_addr) */ + perror("telnet: Unable to connect to remote host"); + return 0; + } + connected++; +#if defined(AUTHENTICATION) || defined(ENCRYPTION) + auth_encrypt_connect(connected); +#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ + } while (connected == 0); + cmdrc(hostp, hostname); + if (autologin && user == NULL) { + struct passwd *pw; + + user = getenv("USER"); + if (user == NULL || + (pw = getpwnam(user)) && pw->pw_uid != getuid()) { + if (pw = getpwuid(getuid())) + user = pw->pw_name; + else + user = NULL; + } + } + if (user) { + env_define((unsigned char *)"USER", (unsigned char *)user); + env_export((unsigned char *)"USER"); + } + (void) call(status, "status", "notmuch", 0); + if (setjmp(peerdied) == 0) + telnet(user); + (void) NetClose(net); + ExitString("Connection closed by foreign host.\n",1); + /*NOTREACHED*/ +} + +#define HELPINDENT (sizeof ("connect")) + +static char + openhelp[] = "connect to a site", + closehelp[] = "close current connection", + logouthelp[] = "forcibly logout remote user and close the connection", + quithelp[] = "exit telnet", + statushelp[] = "print status information", + helphelp[] = "print help information", + sendhelp[] = "transmit special characters ('send ?' for more)", + sethelp[] = "set operating parameters ('set ?' for more)", + unsethelp[] = "unset operating parameters ('unset ?' for more)", + togglestring[] ="toggle operating parameters ('toggle ?' for more)", + slchelp[] = "change state of special charaters ('slc ?' for more)", + displayhelp[] = "display operating parameters", +#if defined(TN3270) && defined(unix) + transcomhelp[] = "specify Unix command for transparent mode pipe", +#endif /* defined(TN3270) && defined(unix) */ +#if defined(AUTHENTICATION) + authhelp[] = "turn on (off) authentication ('auth ?' for more)", +#endif +#ifdef ENCRYPTION + encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", +#endif /* ENCRYPTION */ +#if defined(unix) + zhelp[] = "suspend telnet", +#endif /* defined(unix) */ + shellhelp[] = "invoke a subshell", + envhelp[] = "change environment variables ('environ ?' for more)", + modestring[] = "try to enter line or character mode ('mode ?' for more)"; + +static int help(); + +static Command cmdtab[] = { + { "close", closehelp, bye, 1 }, + { "logout", logouthelp, logout, 1 }, + { "display", displayhelp, display, 0 }, + { "mode", modestring, modecmd, 0 }, + { "open", openhelp, tn, 0 }, + { "quit", quithelp, quit, 0 }, + { "send", sendhelp, sendcmd, 0 }, + { "set", sethelp, setcmd, 0 }, + { "unset", unsethelp, unsetcmd, 0 }, + { "status", statushelp, status, 0 }, + { "toggle", togglestring, toggle, 0 }, + { "slc", slchelp, slccmd, 0 }, +#if defined(TN3270) && defined(unix) + { "transcom", transcomhelp, settranscom, 0 }, +#endif /* defined(TN3270) && defined(unix) */ +#if defined(AUTHENTICATION) + { "auth", authhelp, auth_cmd, 0 }, +#endif +#ifdef ENCRYPTION + { "encrypt", encrypthelp, encrypt_cmd, 0 }, +#endif /* ENCRYPTION */ +#if defined(unix) + { "z", zhelp, suspend, 0 }, +#endif /* defined(unix) */ +#if defined(TN3270) + { "!", shellhelp, shell, 1 }, +#else + { "!", shellhelp, shell, 0 }, +#endif + { "environ", envhelp, env_cmd, 0 }, + { "?", helphelp, help, 0 }, + 0 +}; + +static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; +static char escapehelp[] = "deprecated command -- use 'set escape' instead"; + +static Command cmdtab2[] = { + { "help", 0, help, 0 }, + { "escape", escapehelp, setescape, 0 }, + { "crmod", crmodhelp, togcrmod, 0 }, + 0 +}; + + +/* + * Call routine with argc, argv set from args (terminated by 0). + */ + + /*VARARGS1*/ + static +call(va_alist) + va_dcl +{ + va_list ap; + typedef int (*intrtn_t)(); + intrtn_t routine; + char *args[100]; + int argno = 0; + + va_start(ap); + routine = (va_arg(ap, intrtn_t)); + while ((args[argno++] = va_arg(ap, char *)) != 0) { + ; + } + va_end(ap); + return (*routine)(argno-1, args); +} + + + static Command * +getcmd(name) + char *name; +{ + Command *cm; + + if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) + return cm; + return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); +} + + void +command(top, tbuf, cnt) + int top; + char *tbuf; + int cnt; +{ + register Command *c; + + setcommandmode(); + if (!top) { + putchar('\n'); +#if defined(unix) + } else { + (void) signal(SIGINT, SIG_DFL); + (void) signal(SIGQUIT, SIG_DFL); +#endif /* defined(unix) */ + } + for (;;) { + if (rlogin == _POSIX_VDISABLE) + printf("%s> ", prompt); + if (tbuf) { + register char *cp; + cp = line; + while (cnt > 0 && (*cp++ = *tbuf++) != '\n') + cnt--; + tbuf = 0; + if (cp == line || *--cp != '\n' || cp == line) + goto getline; + *cp = '\0'; + if (rlogin == _POSIX_VDISABLE) + printf("%s\n", line); + } else { + getline: + if (rlogin != _POSIX_VDISABLE) + printf("%s> ", prompt); + if (fgets(line, sizeof(line), stdin) == NULL) { + if (feof(stdin) || ferror(stdin)) { + (void) quit(); + /*NOTREACHED*/ + } + break; + } + } + if (line[0] == 0) + break; + makeargv(); + if (margv[0] == 0) { + break; + } + c = getcmd(margv[0]); + if (Ambiguous(c)) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + if (c->needconnect && !connected) { + printf("?Need to be connected first.\n"); + continue; + } + if ((*c->handler)(margc, margv)) { + break; + } + } + if (!top) { + if (!connected) { + longjmp(toplevel, 1); + /*NOTREACHED*/ + } +#if defined(TN3270) + if (shell_active == 0) { + setconnmode(0); + } +#else /* defined(TN3270) */ + setconnmode(0); +#endif /* defined(TN3270) */ + } +} + +/* + * Help command. + */ + static +help(argc, argv) + int argc; + char *argv[]; +{ + register Command *c; + + if (argc == 1) { + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->name; c++) + if (c->help) { + printf("%-*s\t%s\n", HELPINDENT, c->name, + c->help); + } + return 0; + } + while (--argc > 0) { + register char *arg; + arg = *++argv; + c = getcmd(arg); + if (Ambiguous(c)) + printf("?Ambiguous help command %s\n", arg); + else if (c == (Command *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%s\n", c->help); + } + return 0; +} + +static char *rcname = 0; +static char rcbuf[128]; + +cmdrc(m1, m2) + char *m1, *m2; +{ + register Command *c; + FILE *rcfile; + int gotmachine = 0; + int l1 = strlen(m1); + int l2 = strlen(m2); + char m1save[64]; + + if (skiprc) + return; + + strcpy(m1save, m1); + m1 = m1save; + + if (rcname == 0) { + rcname = getenv("HOME"); + if (rcname) + strcpy(rcbuf, rcname); + else + rcbuf[0] = '\0'; + strcat(rcbuf, "/.telnetrc"); + rcname = rcbuf; + } + + if ((rcfile = fopen(rcname, "r")) == 0) { + return; + } + + for (;;) { + if (fgets(line, sizeof(line), rcfile) == NULL) + break; + if (line[0] == 0) + break; + if (line[0] == '#') + continue; + if (gotmachine) { + if (!isspace(line[0])) + gotmachine = 0; + } + if (gotmachine == 0) { + if (isspace(line[0])) + continue; + if (strncasecmp(line, m1, l1) == 0) + strncpy(line, &line[l1], sizeof(line) - l1); + else if (strncasecmp(line, m2, l2) == 0) + strncpy(line, &line[l2], sizeof(line) - l2); + else if (strncasecmp(line, "DEFAULT", 7) == 0) + strncpy(line, &line[7], sizeof(line) - 7); + else + continue; + if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') + continue; + gotmachine = 1; + } + makeargv(); + if (margv[0] == 0) + continue; + c = getcmd(margv[0]); + if (Ambiguous(c)) { + printf("?Ambiguous command: %s\n", margv[0]); + continue; + } + if (c == 0) { + printf("?Invalid command: %s\n", margv[0]); + continue; + } + /* + * This should never happen... + */ + if (c->needconnect && !connected) { + printf("?Need to be connected first for %s.\n", margv[0]); + continue; + } + (*c->handler)(margc, margv); + } + fclose(rcfile); +} + +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) + +/* + * Source route is handed in as + * [!]@hop1@hop2...[@|:]dst + * If the leading ! is present, it is a + * strict source route, otherwise it is + * assmed to be a loose source route. + * + * We fill in the source route option as + * hop1,hop2,hop3...dest + * and return a pointer to hop1, which will + * be the address to connect() to. + * + * Arguments: + * arg: pointer to route list to decipher + * + * cpp: If *cpp is not equal to NULL, this is a + * pointer to a pointer to a character array + * that should be filled in with the option. + * + * lenp: pointer to an integer that contains the + * length of *cpp if *cpp != NULL. + * + * Return values: + * + * Returns the address of the host to connect to. If the + * return value is -1, there was a syntax error in the + * option, either unknown characters, or too many hosts. + * If the return value is 0, one of the hostnames in the + * path is unknown, and *cpp is set to point to the bad + * hostname. + * + * *cpp: If *cpp was equal to NULL, it will be filled + * in with a pointer to our static area that has + * the option filled in. This will be 32bit aligned. + * + * *lenp: This will be filled in with how long the option + * pointed to by *cpp is. + * + */ + unsigned long +sourceroute(arg, cpp, lenp) + char *arg; + char **cpp; + int *lenp; +{ + static char lsr[44]; +#ifdef sysV88 + static IOPTN ipopt; +#endif + char *cp, *cp2, *lsrp, *lsrep; + register int tmp; + struct in_addr sin_addr; + register struct hostent *host = 0; + register char c; + + /* + * Verify the arguments, and make sure we have + * at least 7 bytes for the option. + */ + if (cpp == NULL || lenp == NULL) + return((unsigned long)-1); + if (*cpp != NULL && *lenp < 7) + return((unsigned long)-1); + /* + * Decide whether we have a buffer passed to us, + * or if we need to use our own static buffer. + */ + if (*cpp) { + lsrp = *cpp; + lsrep = lsrp + *lenp; + } else { + *cpp = lsrp = lsr; + lsrep = lsrp + 44; + } + + cp = arg; + + /* + * Next, decide whether we have a loose source + * route or a strict source route, and fill in + * the begining of the option. + */ +#ifndef sysV88 + if (*cp == '!') { + cp++; + *lsrp++ = IPOPT_SSRR; + } else + *lsrp++ = IPOPT_LSRR; +#else + if (*cp == '!') { + cp++; + ipopt.io_type = IPOPT_SSRR; + } else + ipopt.io_type = IPOPT_LSRR; +#endif + + if (*cp != '@') + return((unsigned long)-1); + +#ifndef sysV88 + lsrp++; /* skip over length, we'll fill it in later */ + *lsrp++ = 4; +#endif + + cp++; + + sin_addr.s_addr = 0; + + for (c = 0;;) { + if (c == ':') + cp2 = 0; + else for (cp2 = cp; c = *cp2; cp2++) { + if (c == ',') { + *cp2++ = '\0'; + if (*cp2 == '@') + cp2++; + } else if (c == '@') { + *cp2++ = '\0'; + } else if (c == ':') { + *cp2++ = '\0'; + } else + continue; + break; + } + if (!c) + cp2 = 0; + + if ((tmp = inet_addr(cp)) != -1) { + sin_addr.s_addr = tmp; + } else if (host = gethostbyname(cp)) { +#if defined(h_addr) + memcpy((caddr_t)&sin_addr, + host->h_addr_list[0], host->h_length); +#else + memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length); +#endif + } else { + *cpp = cp; + return(0); + } + memcpy(lsrp, (char *)&sin_addr, 4); + lsrp += 4; + if (cp2) + cp = cp2; + else + break; + /* + * Check to make sure there is space for next address + */ + if (lsrp + 4 > lsrep) + return((unsigned long)-1); + } +#ifndef sysV88 + if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { + *cpp = 0; + *lenp = 0; + return((unsigned long)-1); + } + *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ + *lenp = lsrp - *cpp; +#else + ipopt.io_len = lsrp - *cpp; + if (ipopt.io_len <= 5) { /* Is 3 better ? */ + *cpp = 0; + *lenp = 0; + return((unsigned long)-1); + } + *lenp = sizeof(ipopt); + *cpp = (char *) &ipopt; +#endif + return(sin_addr.s_addr); +} +#endif diff --git a/usr.bin/telnet/defines.h b/usr.bin/telnet/defines.h new file mode 100644 index 0000000..0978173 --- /dev/null +++ b/usr.bin/telnet/defines.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)defines.h 8.1 (Berkeley) 6/6/93 + */ + +#define settimer(x) clocks.x = clocks.system++ + +#if !defined(TN3270) + +#define SetIn3270() + +#endif /* !defined(TN3270) */ + +#define NETADD(c) { *netoring.supply = c; ring_supplied(&netoring, 1); } +#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } +#define NETBYTES() (ring_full_count(&netoring)) +#define NETROOM() (ring_empty_count(&netoring)) + +#define TTYADD(c) if (!(SYNCHing||flushout)) { \ + *ttyoring.supply = c; \ + ring_supplied(&ttyoring, 1); \ + } +#define TTYBYTES() (ring_full_count(&ttyoring)) +#define TTYROOM() (ring_empty_count(&ttyoring)) + +/* Various modes */ +#define MODE_LOCAL_CHARS(m) ((m)&(MODE_EDIT|MODE_TRAPSIG)) +#define MODE_LOCAL_ECHO(m) ((m)&MODE_ECHO) +#define MODE_COMMAND_LINE(m) ((m)==-1) + +#define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */ diff --git a/usr.bin/telnet/externs.h b/usr.bin/telnet/externs.h new file mode 100644 index 0000000..b721992 --- /dev/null +++ b/usr.bin/telnet/externs.h @@ -0,0 +1,481 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)externs.h 8.2 (Berkeley) 12/15/93 + */ + +#ifndef BSD +# define BSD 43 +#endif + +/* + * ucb stdio.h defines BSD as something wierd + */ +#if defined(sun) && defined(__svr4__) +#define BSD 43 +#endif + +#ifndef USE_TERMIO +# if BSD > 43 || defined(SYSV_TERMIO) +# define USE_TERMIO +# endif +#endif + +#include +#include +#if defined(CRAY) && !defined(NO_BSD_SETJMP) +#include +#endif +#ifndef FILIO_H +#include +#else +#include +#endif +#ifdef CRAY +# include +#endif /* CRAY */ +#ifdef USE_TERMIO +# ifndef VINTR +# ifdef SYSV_TERMIO +# include +# else +# include +# define termio termios +# endif +# endif +#endif +#if defined(NO_CC_T) || !defined(USE_TERMIO) +# if !defined(USE_TERMIO) +typedef char cc_t; +# else +typedef unsigned char cc_t; +# endif +#endif + +#ifndef NO_STRING_H +#include +#endif +#include + +#ifndef _POSIX_VDISABLE +# ifdef sun +# include /* pick up VDISABLE definition, mayby */ +# endif +# ifdef VDISABLE +# define _POSIX_VDISABLE VDISABLE +# else +# define _POSIX_VDISABLE ((cc_t)'\377') +# endif +#endif + +#define SUBBUFSIZE 256 + +#ifndef CRAY +extern int errno; /* outside this world */ +#endif /* !CRAY */ + +#if !defined(P) +# ifdef __STDC__ +# define P(x) x +# else +# define P(x) () +# endif +#endif + +extern int + autologin, /* Autologin enabled */ + skiprc, /* Don't process the ~/.telnetrc file */ + eight, /* use eight bit mode (binary in and/or out */ + flushout, /* flush output */ + connected, /* Are we connected to the other side? */ + globalmode, /* Mode tty should be in */ + In3270, /* Are we in 3270 mode? */ + telnetport, /* Are we connected to the telnet port? */ + localflow, /* Flow control handled locally */ + restartany, /* If flow control, restart output on any character */ + localchars, /* we recognize interrupt/quit */ + donelclchars, /* the user has set "localchars" */ + showoptions, + net, /* Network file descriptor */ + tin, /* Terminal input file descriptor */ + tout, /* Terminal output file descriptor */ + crlf, /* Should '\r' be mapped to (or )? */ + autoflush, /* flush output when interrupting? */ + autosynch, /* send interrupt characters with SYNCH? */ + SYNCHing, /* Is the stream in telnet SYNCH mode? */ + donebinarytoggle, /* the user has put us in binary */ + dontlecho, /* do we suppress local echoing right now? */ + crmod, + netdata, /* Print out network data flow */ + prettydump, /* Print "netdata" output in user readable format */ +#if defined(unix) +#if defined(TN3270) + cursesdata, /* Print out curses data flow */ + apitrace, /* Trace API transactions */ +#endif /* defined(TN3270) */ + termdata, /* Print out terminal data flow */ +#endif /* defined(unix) */ + debug; /* Debug level */ + +extern cc_t escape; /* Escape to command mode */ +extern cc_t rlogin; /* Rlogin mode escape character */ +#ifdef KLUDGELINEMODE +extern cc_t echoc; /* Toggle local echoing */ +#endif + +extern char + *prompt; /* Prompt for command. */ + +extern char + doopt[], + dont[], + will[], + wont[], + options[], /* All the little options */ + *hostname; /* Who are we connected to? */ +#ifdef ENCRYPTION +extern void (*encrypt_output) P((unsigned char *, int)); +extern int (*decrypt_input) P((int)); +#endif /* ENCRYPTION */ + +/* + * We keep track of each side of the option negotiation. + */ + +#define MY_STATE_WILL 0x01 +#define MY_WANT_STATE_WILL 0x02 +#define MY_STATE_DO 0x04 +#define MY_WANT_STATE_DO 0x08 + +/* + * Macros to check the current state of things + */ + +#define my_state_is_do(opt) (options[opt]&MY_STATE_DO) +#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL) +#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO) +#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL) + +#define my_state_is_dont(opt) (!my_state_is_do(opt)) +#define my_state_is_wont(opt) (!my_state_is_will(opt)) +#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) +#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) + +#define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;} +#define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;} +#define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;} +#define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;} + +#define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;} +#define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;} +#define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;} +#define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;} + +/* + * Make everything symetrical + */ + +#define HIS_STATE_WILL MY_STATE_DO +#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO +#define HIS_STATE_DO MY_STATE_WILL +#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL + +#define his_state_is_do my_state_is_will +#define his_state_is_will my_state_is_do +#define his_want_state_is_do my_want_state_is_will +#define his_want_state_is_will my_want_state_is_do + +#define his_state_is_dont my_state_is_wont +#define his_state_is_wont my_state_is_dont +#define his_want_state_is_dont my_want_state_is_wont +#define his_want_state_is_wont my_want_state_is_dont + +#define set_his_state_do set_my_state_will +#define set_his_state_will set_my_state_do +#define set_his_want_state_do set_my_want_state_will +#define set_his_want_state_will set_my_want_state_do + +#define set_his_state_dont set_my_state_wont +#define set_his_state_wont set_my_state_dont +#define set_his_want_state_dont set_my_want_state_wont +#define set_his_want_state_wont set_my_want_state_dont + + +extern FILE + *NetTrace; /* Where debugging output goes */ +extern unsigned char + NetTraceFile[]; /* Name of file where debugging output goes */ +extern void + SetNetTrace P((char *)); /* Function to change where debugging goes */ + +extern jmp_buf + peerdied, + toplevel; /* For error conditions. */ + +extern void + command P((int, char *, int)), + Dump P((int, unsigned char *, int)), + init_3270 P((void)), + printoption P((char *, int, int)), + printsub P((int, unsigned char *, int)), + sendnaws P((void)), + setconnmode P((int)), + setcommandmode P((void)), + setneturg P((void)), + sys_telnet_init P((void)), + telnet P((char *)), + tel_enter_binary P((int)), + TerminalFlushOutput P((void)), + TerminalNewMode P((int)), + TerminalRestoreState P((void)), + TerminalSaveState P((void)), + tninit P((void)), + upcase P((char *)), + willoption P((int)), + wontoption P((int)); + +extern void + send_do P((int, int)), + send_dont P((int, int)), + send_will P((int, int)), + send_wont P((int, int)); + +extern void + lm_will P((unsigned char *, int)), + lm_wont P((unsigned char *, int)), + lm_do P((unsigned char *, int)), + lm_dont P((unsigned char *, int)), + lm_mode P((unsigned char *, int, int)); + +extern void + slc_init P((void)), + slcstate P((void)), + slc_mode_export P((void)), + slc_mode_import P((int)), + slc_import P((int)), + slc_export P((void)), + slc P((unsigned char *, int)), + slc_check P((void)), + slc_start_reply P((void)), + slc_add_reply P((int, int, int)), + slc_end_reply P((void)); +extern int + slc_update P((void)); + +extern void + env_opt P((unsigned char *, int)), + env_opt_start P((void)), + env_opt_start_info P((void)), + env_opt_add P((unsigned char *)), + env_opt_end P((int)); + +extern unsigned char + *env_default P((int, int)), + *env_getvalue P((unsigned char *)); + +extern int + get_status P((void)), + dosynch P((void)); + +extern cc_t + *tcval P((int)); + +#ifndef USE_TERMIO + +extern struct tchars ntc; +extern struct ltchars nltc; +extern struct sgttyb nttyb; + +# define termEofChar ntc.t_eofc +# define termEraseChar nttyb.sg_erase +# define termFlushChar nltc.t_flushc +# define termIntChar ntc.t_intrc +# define termKillChar nttyb.sg_kill +# define termLiteralNextChar nltc.t_lnextc +# define termQuitChar ntc.t_quitc +# define termSuspChar nltc.t_suspc +# define termRprntChar nltc.t_rprntc +# define termWerasChar nltc.t_werasc +# define termStartChar ntc.t_startc +# define termStopChar ntc.t_stopc +# define termForw1Char ntc.t_brkc +extern cc_t termForw2Char; +extern cc_t termAytChar; + +# define termEofCharp (cc_t *)&ntc.t_eofc +# define termEraseCharp (cc_t *)&nttyb.sg_erase +# define termFlushCharp (cc_t *)&nltc.t_flushc +# define termIntCharp (cc_t *)&ntc.t_intrc +# define termKillCharp (cc_t *)&nttyb.sg_kill +# define termLiteralNextCharp (cc_t *)&nltc.t_lnextc +# define termQuitCharp (cc_t *)&ntc.t_quitc +# define termSuspCharp (cc_t *)&nltc.t_suspc +# define termRprntCharp (cc_t *)&nltc.t_rprntc +# define termWerasCharp (cc_t *)&nltc.t_werasc +# define termStartCharp (cc_t *)&ntc.t_startc +# define termStopCharp (cc_t *)&ntc.t_stopc +# define termForw1Charp (cc_t *)&ntc.t_brkc +# define termForw2Charp (cc_t *)&termForw2Char +# define termAytCharp (cc_t *)&termAytChar + +# else + +extern struct termio new_tc; + +# define termEofChar new_tc.c_cc[VEOF] +# define termEraseChar new_tc.c_cc[VERASE] +# define termIntChar new_tc.c_cc[VINTR] +# define termKillChar new_tc.c_cc[VKILL] +# define termQuitChar new_tc.c_cc[VQUIT] + +# ifndef VSUSP +extern cc_t termSuspChar; +# else +# define termSuspChar new_tc.c_cc[VSUSP] +# endif +# if defined(VFLUSHO) && !defined(VDISCARD) +# define VDISCARD VFLUSHO +# endif +# ifndef VDISCARD +extern cc_t termFlushChar; +# else +# define termFlushChar new_tc.c_cc[VDISCARD] +# endif +# ifndef VWERASE +extern cc_t termWerasChar; +# else +# define termWerasChar new_tc.c_cc[VWERASE] +# endif +# ifndef VREPRINT +extern cc_t termRprntChar; +# else +# define termRprntChar new_tc.c_cc[VREPRINT] +# endif +# ifndef VLNEXT +extern cc_t termLiteralNextChar; +# else +# define termLiteralNextChar new_tc.c_cc[VLNEXT] +# endif +# ifndef VSTART +extern cc_t termStartChar; +# else +# define termStartChar new_tc.c_cc[VSTART] +# endif +# ifndef VSTOP +extern cc_t termStopChar; +# else +# define termStopChar new_tc.c_cc[VSTOP] +# endif +# ifndef VEOL +extern cc_t termForw1Char; +# else +# define termForw1Char new_tc.c_cc[VEOL] +# endif +# ifndef VEOL2 +extern cc_t termForw2Char; +# else +# define termForw2Char new_tc.c_cc[VEOL] +# endif +# ifndef VSTATUS +extern cc_t termAytChar; +#else +# define termAytChar new_tc.c_cc[VSTATUS] +#endif + +# if !defined(CRAY) || defined(__STDC__) +# define termEofCharp &termEofChar +# define termEraseCharp &termEraseChar +# define termIntCharp &termIntChar +# define termKillCharp &termKillChar +# define termQuitCharp &termQuitChar +# define termSuspCharp &termSuspChar +# define termFlushCharp &termFlushChar +# define termWerasCharp &termWerasChar +# define termRprntCharp &termRprntChar +# define termLiteralNextCharp &termLiteralNextChar +# define termStartCharp &termStartChar +# define termStopCharp &termStopChar +# define termForw1Charp &termForw1Char +# define termForw2Charp &termForw2Char +# define termAytCharp &termAytChar +# else + /* Work around a compiler bug */ +# define termEofCharp 0 +# define termEraseCharp 0 +# define termIntCharp 0 +# define termKillCharp 0 +# define termQuitCharp 0 +# define termSuspCharp 0 +# define termFlushCharp 0 +# define termWerasCharp 0 +# define termRprntCharp 0 +# define termLiteralNextCharp 0 +# define termStartCharp 0 +# define termStopCharp 0 +# define termForw1Charp 0 +# define termForw2Charp 0 +# define termAytCharp 0 +# endif +#endif + + +/* Ring buffer structures which are shared */ + +extern Ring + netoring, + netiring, + ttyoring, + ttyiring; + +/* Tn3270 section */ +#if defined(TN3270) + +extern int + HaveInput, /* Whether an asynchronous I/O indication came in */ + noasynchtty, /* Don't do signals on I/O (SIGURG, SIGIO) */ + noasynchnet, /* Don't do signals on I/O (SIGURG, SIGIO) */ + sigiocount, /* Count of SIGIO receptions */ + shell_active; /* Subshell is active */ + +extern char + *Ibackp, /* Oldest byte of 3270 data */ + Ibuf[], /* 3270 buffer */ + *Ifrontp, /* Where next 3270 byte goes */ + tline[], + *transcom; /* Transparent command */ + +extern int + settranscom P((int, char**)); + +extern void + inputAvailable P((int)); +#endif /* defined(TN3270) */ diff --git a/usr.bin/telnet/fdset.h b/usr.bin/telnet/fdset.h new file mode 100644 index 0000000..045bb72 --- /dev/null +++ b/usr.bin/telnet/fdset.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)fdset.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * The following is defined just in case someone should want to run + * this telnet on a 4.2 system. + * + */ + +#ifndef FD_SETSIZE + +#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) +#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) +#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) +#define FD_ZERO(p) ((p)->fds_bits[0] = 0) + +#endif diff --git a/usr.bin/telnet/general.h b/usr.bin/telnet/general.h new file mode 100644 index 0000000..4efa951 --- /dev/null +++ b/usr.bin/telnet/general.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)general.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Some general definitions. + */ + + +#define numberof(x) (sizeof x/sizeof x[0]) +#define highestof(x) (numberof(x)-1) + +#define ClearElement(x) memset((char *)&x, 0, sizeof x) +#define ClearArray(x) memset((char *)x, 0, sizeof x) diff --git a/usr.bin/telnet/krb4-proto.h b/usr.bin/telnet/krb4-proto.h new file mode 100644 index 0000000..75f6d41 --- /dev/null +++ b/usr.bin/telnet/krb4-proto.h @@ -0,0 +1,207 @@ +#ifdef __STDC__ +# define P(s) s +#else +# define P(s) () +#endif + +/* add_ticket.c */ +int add_ticket P((KTEXT , int , char *, int , char *, char *, char *, int , KTEXT )); + +/* cr_err_reply.c */ +void cr_err_reply P((KTEXT , char *, char *, char *, u_long , u_long , char *)); + +/* create_auth_reply.c */ +KTEXT create_auth_reply P((char *, char *, char *, long , int , unsigned long , int , KTEXT )); + +/* create_ciph.c */ +int create_ciph P((KTEXT , C_Block , char *, char *, char *, unsigned long , int , KTEXT , unsigned long , C_Block )); + +/* create_death_packet.c */ +KTEXT krb_create_death_packet P((char *)); + +/* create_ticket.c */ +int krb_create_ticket P((KTEXT , unsigned int , char *, char *, char *, long , char *, int , long , char *, char *, C_Block )); + +/* debug_decl.c */ + +/* decomp_ticket.c */ +int decomp_ticket P((KTEXT , unsigned char *, char *, char *, char *, unsigned long *, C_Block , int *, unsigned long *, char *, char *, C_Block , Key_schedule )); + +/* dest_tkt.c */ +int dest_tkt P((void )); + +/* extract_ticket.c */ +int extract_ticket P((KTEXT , int , char *, int *, int *, char *, KTEXT )); + +/* fgetst.c */ +int fgetst P((FILE *, char *, int )); + +/* get_ad_tkt.c */ +int get_ad_tkt P((char *, char *, char *, int )); + +/* get_admhst.c */ +int krb_get_admhst P((char *, char *, int )); + +/* get_cred.c */ +int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); + +/* get_in_tkt.c */ +int krb_get_pw_in_tkt P((char *, char *, char *, char *, char *, int , char *)); +int placebo_read_password P((des_cblock *, char *, int )); +int placebo_read_pw_string P((char *, int , char *, int )); + +/* get_krbhst.c */ +int krb_get_krbhst P((char *, char *, int )); + +/* get_krbrlm.c */ +int krb_get_lrealm P((char *, int )); + +/* get_phost.c */ +char *krb_get_phost P((char *)); + +/* get_pw_tkt.c */ +int get_pw_tkt P((char *, char *, char *, char *)); + +/* get_request.c */ +int get_request P((KTEXT , int , char **, char **)); + +/* get_svc_in_tkt.c */ +int krb_get_svc_in_tkt P((char *, char *, char *, char *, char *, int , char *)); + +/* get_tf_fullname.c */ +int krb_get_tf_fullname P((char *, char *, char *, char *)); + +/* get_tf_realm.c */ +int krb_get_tf_realm P((char *, char *)); + +/* getopt.c */ +int getopt P((int , char **, char *)); + +/* getrealm.c */ +char *krb_realmofhost P((char *)); + +/* getst.c */ +int getst P((int , char *, int )); + +/* in_tkt.c */ +int in_tkt P((char *, char *)); + +/* k_gethostname.c */ +int k_gethostname P((char *, int )); + +/* klog.c */ +char *klog P((int , char *, int , int , int , int , int , int , int , int , int , int )); +int kset_logfile P((char *)); + +/* kname_parse.c */ +int kname_parse P((char *, char *, char *, char *)); +int k_isname P((char *)); +int k_isinst P((char *)); +int k_isrealm P((char *)); + +/* kntoln.c */ +int krb_kntoln P((AUTH_DAT *, char *)); + +/* krb_err_txt.c */ + +/* krb_get_in_tkt.c */ +int krb_get_in_tkt P((char *, char *, char *, char *, char *, int , int (*key_proc )(), int (*decrypt_proc )(), char *)); + +/* kuserok.c */ +int kuserok P((AUTH_DAT *, char *)); + +/* log.c */ +void log P((char *, int , int , int , int , int , int , int , int , int , int )); +int set_logfile P((char *)); +int new_log P((long , char *)); + +/* mk_err.c */ +long krb_mk_err P((u_char *, long , char *)); + +/* mk_priv.c */ +long krb_mk_priv P((u_char *, u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *)); + +/* mk_req.c */ +int krb_mk_req P((KTEXT , char *, char *, char *, long )); +int krb_set_lifetime P((int )); + +/* mk_safe.c */ +long krb_mk_safe P((u_char *, u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *)); + +/* month_sname.c */ +char *month_sname P((int )); + +/* netread.c */ +int krb_net_read P((int , char *, int )); + +/* netwrite.c */ +int krb_net_write P((int , char *, int )); + +/* one.c */ + +/* pkt_cipher.c */ +KTEXT pkt_cipher P((KTEXT )); + +/* pkt_clen.c */ +int pkt_clen P((KTEXT )); + +/* rd_err.c */ +int krb_rd_err P((u_char *, u_long , long *, MSG_DAT *)); + +/* rd_priv.c */ +long krb_rd_priv P((u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *)); + +/* rd_req.c */ +int krb_set_key P((char *, int )); +int krb_rd_req P((KTEXT , char *, char *, long , AUTH_DAT *, char *)); + +/* rd_safe.c */ +long krb_rd_safe P((u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *)); + +/* read_service_key.c */ +int read_service_key P((char *, char *, char *, int , char *, char *)); + +/* recvauth.c */ +int krb_recvauth P((long , int , KTEXT , char *, char *, struct sockaddr_in *, struct sockaddr_in *, AUTH_DAT *, char *, Key_schedule , char *)); + +/* save_credentials.c */ +int save_credentials P((char *, char *, char *, C_Block , int , int , KTEXT , long )); + +/* send_to_kdc.c */ +int send_to_kdc P((KTEXT , KTEXT , char *)); + +/* sendauth.c */ +int krb_sendauth P((long , int , KTEXT , char *, char *, char *, u_long , MSG_DAT *, CREDENTIALS *, Key_schedule , struct sockaddr_in *, struct sockaddr_in *, char *)); +int krb_sendsvc P((int , char *)); + +/* setenv.c */ +int setenv P((char *, char *, int )); +void unsetenv P((char *)); +char *getenv P((char *)); +char *_findenv P((char *, int *)); + +/* stime.c */ +char *stime P((long *)); + +/* tf_shm.c */ +int krb_shm_create P((char *)); +int krb_is_diskless P((void )); +int krb_shm_dest P((char *)); + +/* tf_util.c */ +int tf_init P((char *, int )); +int tf_get_pname P((char *)); +int tf_get_pinst P((char *)); +int tf_get_cred P((CREDENTIALS *)); +int tf_close P((void )); +int tf_save_cred P((char *, char *, char *, C_Block , int , int , KTEXT , long )); + +/* tkt_string.c */ +char *tkt_string P((void )); +void krb_set_tkt_string P((char *)); + +/* util.c */ +int ad_print P((AUTH_DAT *)); +int placebo_cblock_print P((des_cblock )); + +#undef P diff --git a/usr.bin/telnet/main.c b/usr.bin/telnet/main.c new file mode 100644 index 0000000..ce22840 --- /dev/null +++ b/usr.bin/telnet/main.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1988, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +#include + +#include "ring.h" +#include "externs.h" +#include "defines.h" + +/* These values need to be the same as defined in libtelnet/kerberos5.c */ +/* Either define them in both places, or put in some common header file. */ +#define OPTS_FORWARD_CREDS 0x00000002 +#define OPTS_FORWARDABLE_CREDS 0x00000001 + +#if 0 +#define FORWARD +#endif + +/* + * Initialize variables. + */ + void +tninit() +{ + init_terminal(); + + init_network(); + + init_telnet(); + + init_sys(); + +#if defined(TN3270) + init_3270(); +#endif +} + + void +usage() +{ + fprintf(stderr, "Usage: %s %s%s%s%s\n", + prompt, +#ifdef AUTHENTICATION + "[-8] [-E] [-K] [-L] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]", + "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] ", +#else + "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]", + "\n\t[-n tracefile]", +#endif +#if defined(TN3270) && defined(unix) +# ifdef AUTHENTICATION + "[-noasynch] [-noasynctty]\n\t[-noasyncnet] [-r] [-t transcom] ", +# else + "[-noasynch] [-noasynctty] [-noasyncnet] [-r]\n\t[-t transcom]", +# endif +#else + "[-r] ", +#endif +#ifdef ENCRYPTION + "[-x] [host-name [port]]" +#else /* ENCRYPTION */ + "[host-name [port]]" +#endif /* ENCRYPTION */ + ); + exit(1); +} + +/* + * main. Parse arguments, invoke the protocol or command parser. + */ + + +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + int ch; + char *user, *strrchr(); +#ifdef FORWARD + extern int forward_flags; +#endif /* FORWARD */ + + tninit(); /* Clear out things */ +#if defined(CRAY) && !defined(__STDC__) + _setlist_init(); /* Work around compiler bug */ +#endif + + TerminalSaveState(); + + if (prompt = strrchr(argv[0], '/')) + ++prompt; + else + prompt = argv[0]; + + user = NULL; + + rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; + autologin = -1; + + while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) { + switch(ch) { + case '8': + eight = 3; /* binary output and input */ + break; + case 'E': + rlogin = escape = _POSIX_VDISABLE; + break; + case 'K': +#ifdef AUTHENTICATION + autologin = 0; +#endif + break; + case 'L': + eight |= 2; /* binary output only */ + break; + case 'S': + { +#ifdef HAS_GETTOS + extern int tos; + + if ((tos = parsetos(optarg, "tcp")) < 0) + fprintf(stderr, "%s%s%s%s\n", + prompt, ": Bad TOS argument '", + optarg, + "; will try to use default TOS"); +#else + fprintf(stderr, + "%s: Warning: -S ignored, no parsetos() support.\n", + prompt); +#endif + } + break; + case 'X': +#ifdef AUTHENTICATION + auth_disable_name(optarg); +#endif + break; + case 'a': + autologin = 1; + break; + case 'c': + skiprc = 1; + break; + case 'd': + debug = 1; + break; + case 'e': + set_escape_char(optarg); + break; + case 'f': +#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) + if (forward_flags & OPTS_FORWARD_CREDS) { + fprintf(stderr, + "%s: Only one of -f and -F allowed.\n", + prompt); + usage(); + } + forward_flags |= OPTS_FORWARD_CREDS; +#else + fprintf(stderr, + "%s: Warning: -f ignored, no Kerberos V5 support.\n", + prompt); +#endif + break; + case 'F': +#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) + if (forward_flags & OPTS_FORWARD_CREDS) { + fprintf(stderr, + "%s: Only one of -f and -F allowed.\n", + prompt); + usage(); + } + forward_flags |= OPTS_FORWARD_CREDS; + forward_flags |= OPTS_FORWARDABLE_CREDS; +#else + fprintf(stderr, + "%s: Warning: -F ignored, no Kerberos V5 support.\n", + prompt); +#endif + break; + case 'k': +#if defined(AUTHENTICATION) && defined(KRB4) + { + extern char *dest_realm, dst_realm_buf[], dst_realm_sz; + dest_realm = dst_realm_buf; + (void)strncpy(dest_realm, optarg, dst_realm_sz); + } +#else + fprintf(stderr, + "%s: Warning: -k ignored, no Kerberos V4 support.\n", + prompt); +#endif + break; + case 'l': + autologin = 1; + user = optarg; + break; + case 'n': +#if defined(TN3270) && defined(unix) + /* distinguish between "-n oasynch" and "-noasynch" */ + if (argv[optind - 1][0] == '-' && argv[optind - 1][1] + == 'n' && argv[optind - 1][2] == 'o') { + if (!strcmp(optarg, "oasynch")) { + noasynchtty = 1; + noasynchnet = 1; + } else if (!strcmp(optarg, "oasynchtty")) + noasynchtty = 1; + else if (!strcmp(optarg, "oasynchnet")) + noasynchnet = 1; + } else +#endif /* defined(TN3270) && defined(unix) */ + SetNetTrace(optarg); + break; + case 'r': + rlogin = '~'; + break; + case 't': +#if defined(TN3270) && defined(unix) + transcom = tline; + (void)strcpy(transcom, optarg); +#else + fprintf(stderr, + "%s: Warning: -t ignored, no TN3270 support.\n", + prompt); +#endif + break; + case 'x': +#ifdef ENCRYPTION + encrypt_auto(1); + decrypt_auto(1); +#else /* ENCRYPTION */ + fprintf(stderr, + "%s: Warning: -x ignored, no ENCRYPT support.\n", + prompt); +#endif /* ENCRYPTION */ + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + if (autologin == -1) + autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1; + + argc -= optind; + argv += optind; + + if (argc) { + char *args[7], **argp = args; + + if (argc > 2) + usage(); + *argp++ = prompt; + if (user) { + *argp++ = "-l"; + *argp++ = user; + } + *argp++ = argv[0]; /* host */ + if (argc > 1) + *argp++ = argv[1]; /* port */ + *argp = 0; + + if (setjmp(toplevel) != 0) + Exit(0); + if (tn(argp - args, args) == 1) + return (0); + else + return (1); + } + (void)setjmp(toplevel); + for (;;) { +#ifdef TN3270 + if (shell_active) + shell_continue(); + else +#endif + command(1, 0, 0); + } +} diff --git a/usr.bin/telnet/network.c b/usr.bin/telnet/network.c new file mode 100644 index 0000000..0fe5cee --- /dev/null +++ b/usr.bin/telnet/network.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +#include +#include +#include + +#include + +#include + +#include "ring.h" + +#include "defines.h" +#include "externs.h" +#include "fdset.h" + +Ring netoring, netiring; +unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ]; + +/* + * Initialize internal network data structures. + */ + + void +init_network() +{ + if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) { + exit(1); + } + if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) { + exit(1); + } + NetTrace = stdout; +} + + +/* + * Check to see if any out-of-band data exists on a socket (for + * Telnet "synch" processing). + */ + + int +stilloob() +{ + static struct timeval timeout = { 0 }; + fd_set excepts; + int value; + + do { + FD_ZERO(&excepts); + FD_SET(net, &excepts); + value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); + } while ((value == -1) && (errno == EINTR)); + + if (value < 0) { + perror("select"); + (void) quit(); + /* NOTREACHED */ + } + if (FD_ISSET(net, &excepts)) { + return 1; + } else { + return 0; + } +} + + +/* + * setneturg() + * + * Sets "neturg" to the current location. + */ + + void +setneturg() +{ + ring_mark(&netoring); +} + + +/* + * netflush + * Send as much data as possible to the network, + * handling requests for urgent data. + * + * The return value indicates whether we did any + * useful work. + */ + + + int +netflush() +{ + register int n, n1; + +#ifdef ENCRYPTION + if (encrypt_output) + ring_encrypt(&netoring, encrypt_output); +#endif /* ENCRYPTION */ + if ((n1 = n = ring_full_consecutive(&netoring)) > 0) { + if (!ring_at_mark(&netoring)) { + n = send(net, (char *)netoring.consume, n, 0); /* normal write */ + } else { + /* + * In 4.2 (and 4.3) systems, there is some question about + * what byte in a sendOOB operation is the "OOB" data. + * To make ourselves compatible, we only send ONE byte + * out of band, the one WE THINK should be OOB (though + * we really have more the TCP philosophy of urgent data + * rather than the Unix philosophy of OOB data). + */ + n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */ + } + } + if (n < 0) { + if (errno != ENOBUFS && errno != EWOULDBLOCK) { + setcommandmode(); + perror(hostname); + (void)NetClose(net); + ring_clear_mark(&netoring); + longjmp(peerdied, -1); + /*NOTREACHED*/ + } + n = 0; + } + if (netdata && n) { + Dump('>', netoring.consume, n); + } + if (n) { + ring_consumed(&netoring, n); + /* + * If we sent all, and more to send, then recurse to pick + * up the other half. + */ + if ((n1 == n) && ring_full_consecutive(&netoring)) { + (void) netflush(); + } + return 1; + } else { + return 0; + } +} diff --git a/usr.bin/telnet/ring.c b/usr.bin/telnet/ring.c new file mode 100644 index 0000000..1080d12 --- /dev/null +++ b/usr.bin/telnet/ring.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)ring.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This defines a structure for a ring buffer. + * + * The circular buffer has two parts: + *((( + * full: [consume, supply) + * empty: [supply, consume) + *]]] + * + */ + +#include +#include + +#ifdef size_t +#undef size_t +#endif + +#include +#ifndef FILIO_H +#include +#endif +#include + +#include "ring.h" +#include "general.h" + +/* Internal macros */ + +#if !defined(MIN) +#define MIN(a,b) (((a)<(b))? (a):(b)) +#endif /* !defined(MIN) */ + +#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ + (a)-(b): (((a)-(b))+(d)->size)) + +#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ + (a)+(c) : (((a)+(c))-(d)->size)) + +#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ + (a)-(c) : (((a)-(c))-(d)->size)) + + +/* + * The following is a clock, used to determine full, empty, etc. + * + * There is some trickiness here. Since the ring buffers are initialized + * to ZERO on allocation, we need to make sure, when interpreting the + * clock, that when the times are EQUAL, then the buffer is FULL. + */ +static u_long ring_clock = 0; + + +#define ring_empty(d) (((d)->consume == (d)->supply) && \ + ((d)->consumetime >= (d)->supplytime)) +#define ring_full(d) (((d)->supply == (d)->consume) && \ + ((d)->supplytime > (d)->consumetime)) + + + + + +/* Buffer state transition routines */ + + ring_init(ring, buffer, count) +Ring *ring; + unsigned char *buffer; + int count; +{ + memset((char *)ring, 0, sizeof *ring); + + ring->size = count; + + ring->supply = ring->consume = ring->bottom = buffer; + + ring->top = ring->bottom+ring->size; + +#ifdef ENCRYPTION + ring->clearto = 0; +#endif /* ENCRYPTION */ + + return 1; +} + +/* Mark routines */ + +/* + * Mark the most recently supplied byte. + */ + + void +ring_mark(ring) + Ring *ring; +{ + ring->mark = ring_decrement(ring, ring->supply, 1); +} + +/* + * Is the ring pointing to the mark? + */ + + int +ring_at_mark(ring) + Ring *ring; +{ + if (ring->mark == ring->consume) { + return 1; + } else { + return 0; + } +} + +/* + * Clear any mark set on the ring. + */ + + void +ring_clear_mark(ring) + Ring *ring; +{ + ring->mark = 0; +} + +/* + * Add characters from current segment to ring buffer. + */ + void +ring_supplied(ring, count) + Ring *ring; + int count; +{ + ring->supply = ring_increment(ring, ring->supply, count); + ring->supplytime = ++ring_clock; +} + +/* + * We have just consumed "c" bytes. + */ + void +ring_consumed(ring, count) + Ring *ring; + int count; +{ + if (count == 0) /* don't update anything */ + return; + + if (ring->mark && + (ring_subtract(ring, ring->mark, ring->consume) < count)) { + ring->mark = 0; + } +#ifdef ENCRYPTION + if (ring->consume < ring->clearto && + ring->clearto <= ring->consume + count) + ring->clearto = 0; + else if (ring->consume + count > ring->top && + ring->bottom <= ring->clearto && + ring->bottom + ((ring->consume + count) - ring->top)) + ring->clearto = 0; +#endif /* ENCRYPTION */ + ring->consume = ring_increment(ring, ring->consume, count); + ring->consumetime = ++ring_clock; + /* + * Try to encourage "ring_empty_consecutive()" to be large. + */ + if (ring_empty(ring)) { + ring->consume = ring->supply = ring->bottom; + } +} + + + +/* Buffer state query routines */ + + +/* Number of bytes that may be supplied */ + int +ring_empty_count(ring) + Ring *ring; +{ + if (ring_empty(ring)) { /* if empty */ + return ring->size; + } else { + return ring_subtract(ring, ring->consume, ring->supply); + } +} + +/* number of CONSECUTIVE bytes that may be supplied */ + int +ring_empty_consecutive(ring) + Ring *ring; +{ + if ((ring->consume < ring->supply) || ring_empty(ring)) { + /* + * if consume is "below" supply, or empty, then + * return distance to the top + */ + return ring_subtract(ring, ring->top, ring->supply); + } else { + /* + * else, return what we may. + */ + return ring_subtract(ring, ring->consume, ring->supply); + } +} + +/* Return the number of bytes that are available for consuming + * (but don't give more than enough to get to cross over set mark) + */ + + int +ring_full_count(ring) + Ring *ring; +{ + if ((ring->mark == 0) || (ring->mark == ring->consume)) { + if (ring_full(ring)) { + return ring->size; /* nothing consumed, but full */ + } else { + return ring_subtract(ring, ring->supply, ring->consume); + } + } else { + return ring_subtract(ring, ring->mark, ring->consume); + } +} + +/* + * Return the number of CONSECUTIVE bytes available for consuming. + * However, don't return more than enough to cross over set mark. + */ + int +ring_full_consecutive(ring) + Ring *ring; +{ + if ((ring->mark == 0) || (ring->mark == ring->consume)) { + if ((ring->supply < ring->consume) || ring_full(ring)) { + return ring_subtract(ring, ring->top, ring->consume); + } else { + return ring_subtract(ring, ring->supply, ring->consume); + } + } else { + if (ring->mark < ring->consume) { + return ring_subtract(ring, ring->top, ring->consume); + } else { /* Else, distance to mark */ + return ring_subtract(ring, ring->mark, ring->consume); + } + } +} + +/* + * Move data into the "supply" portion of of the ring buffer. + */ + void +ring_supply_data(ring, buffer, count) + Ring *ring; + unsigned char *buffer; + int count; +{ + int i; + + while (count) { + i = MIN(count, ring_empty_consecutive(ring)); + memcpy(ring->supply, buffer, i); + ring_supplied(ring, i); + count -= i; + buffer += i; + } +} + +#ifdef notdef + +/* + * Move data from the "consume" portion of the ring buffer + */ + void +ring_consume_data(ring, buffer, count) + Ring *ring; + unsigned char *buffer; + int count; +{ + int i; + + while (count) { + i = MIN(count, ring_full_consecutive(ring)); + memcpy(buffer, ring->consume, i); + ring_consumed(ring, i); + count -= i; + buffer += i; + } +} +#endif + +#ifdef ENCRYPTION + void +ring_encrypt(ring, encryptor) + Ring *ring; + void (*encryptor)(); +{ + unsigned char *s, *c; + + if (ring_empty(ring) || ring->clearto == ring->supply) + return; + + if (!(c = ring->clearto)) + c = ring->consume; + + s = ring->supply; + + if (s <= c) { + (*encryptor)(c, ring->top - c); + (*encryptor)(ring->bottom, s - ring->bottom); + } else + (*encryptor)(c, s - c); + + ring->clearto = ring->supply; +} + + void +ring_clearto(ring) + Ring *ring; +{ + if (!ring_empty(ring)) + ring->clearto = ring->supply; + else + ring->clearto = 0; +} +#endif /* ENCRYPTION */ diff --git a/usr.bin/telnet/ring.h b/usr.bin/telnet/ring.h new file mode 100644 index 0000000..2a36781 --- /dev/null +++ b/usr.bin/telnet/ring.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)ring.h 8.1 (Berkeley) 6/6/93 + */ + +#if defined(P) +# undef P +#endif + +#if defined(__STDC__) || defined(LINT_ARGS) +# define P(x) x +#else +# define P(x) () +#endif + +/* + * This defines a structure for a ring buffer. + * + * The circular buffer has two parts: + *((( + * full: [consume, supply) + * empty: [supply, consume) + *]]] + * + */ +typedef struct { + unsigned char *consume, /* where data comes out of */ + *supply, /* where data comes in to */ + *bottom, /* lowest address in buffer */ + *top, /* highest address+1 in buffer */ + *mark; /* marker (user defined) */ +#ifdef ENCRYPTION + unsigned char *clearto; /* Data to this point is clear text */ + unsigned char *encryyptedto; /* Data is encrypted to here */ +#endif /* ENCRYPTION */ + int size; /* size in bytes of buffer */ + u_long consumetime, /* help us keep straight full, empty, etc. */ + supplytime; +} Ring; + +/* Here are some functions and macros to deal with the ring buffer */ + +/* Initialization routine */ +extern int + ring_init P((Ring *ring, unsigned char *buffer, int count)); + +/* Data movement routines */ +extern void + ring_supply_data P((Ring *ring, unsigned char *buffer, int count)); +#ifdef notdef +extern void + ring_consume_data P((Ring *ring, unsigned char *buffer, int count)); +#endif + +/* Buffer state transition routines */ +extern void + ring_supplied P((Ring *ring, int count)), + ring_consumed P((Ring *ring, int count)); + +/* Buffer state query routines */ +extern int + ring_empty_count P((Ring *ring)), + ring_empty_consecutive P((Ring *ring)), + ring_full_count P((Ring *ring)), + ring_full_consecutive P((Ring *ring)); + +#ifdef ENCRYPTION +extern void + ring_encrypt P((Ring *ring, void (*func)())), + ring_clearto P((Ring *ring)); +#endif /* ENCRYPTION */ + +extern void + ring_clear_mark(), + ring_mark(); diff --git a/usr.bin/telnet/sys_bsd.c b/usr.bin/telnet/sys_bsd.c new file mode 100644 index 0000000..85414e2 --- /dev/null +++ b/usr.bin/telnet/sys_bsd.c @@ -0,0 +1,1167 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)sys_bsd.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +/* + * The following routines try to encapsulate what is system dependent + * (at least between 4.x and dos) which is used in telnet.c. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "ring.h" + +#include "fdset.h" + +#include "defines.h" +#include "externs.h" +#include "types.h" + +#if defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO)) +#define SIG_FUNC_RET void +#else +#define SIG_FUNC_RET int +#endif + +#ifdef SIGINFO +extern SIG_FUNC_RET ayt_status(); +#endif + +int + tout, /* Output file descriptor */ + tin, /* Input file descriptor */ + net; + +#ifndef USE_TERMIO +struct tchars otc = { 0 }, ntc = { 0 }; +struct ltchars oltc = { 0 }, nltc = { 0 }; +struct sgttyb ottyb = { 0 }, nttyb = { 0 }; +int olmode = 0; +# define cfgetispeed(ptr) (ptr)->sg_ispeed +# define cfgetospeed(ptr) (ptr)->sg_ospeed +# define old_tc ottyb + +#else /* USE_TERMIO */ +struct termio old_tc = { 0 }; +extern struct termio new_tc; + +# ifndef TCSANOW +# ifdef TCSETS +# define TCSANOW TCSETS +# define TCSADRAIN TCSETSW +# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) +# else +# ifdef TCSETA +# define TCSANOW TCSETA +# define TCSADRAIN TCSETAW +# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) +# else +# define TCSANOW TIOCSETA +# define TCSADRAIN TIOCSETAW +# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) +# endif +# endif +# define tcsetattr(f, a, t) ioctl(f, a, (char *)t) +# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) +# ifdef CIBAUD +# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) +# else +# define cfgetispeed(ptr) cfgetospeed(ptr) +# endif +# endif /* TCSANOW */ +# ifdef sysV88 +# define TIOCFLUSH TC_PX_DRAIN +# endif +#endif /* USE_TERMIO */ + +static fd_set ibits, obits, xbits; + + + void +init_sys() +{ + tout = fileno(stdout); + tin = fileno(stdin); + FD_ZERO(&ibits); + FD_ZERO(&obits); + FD_ZERO(&xbits); + + errno = 0; +} + + + int +TerminalWrite(buf, n) + char *buf; + int n; +{ + return write(tout, buf, n); +} + + int +TerminalRead(buf, n) + char *buf; + int n; +{ + return read(tin, buf, n); +} + +/* + * + */ + + int +TerminalAutoFlush() +{ +#if defined(LNOFLSH) + int flush; + + ioctl(0, TIOCLGET, (char *)&flush); + return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ +#else /* LNOFLSH */ + return 1; +#endif /* LNOFLSH */ +} + +#ifdef KLUDGELINEMODE +extern int kludgelinemode; +#endif +/* + * TerminalSpecialChars() + * + * Look at an input character to see if it is a special character + * and decide what to do. + * + * Output: + * + * 0 Don't add this character. + * 1 Do add this character + */ + +extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); + + int +TerminalSpecialChars(c) + int c; +{ + if (c == termIntChar) { + intp(); + return 0; + } else if (c == termQuitChar) { +#ifdef KLUDGELINEMODE + if (kludgelinemode) + sendbrk(); + else +#endif + sendabort(); + return 0; + } else if (c == termEofChar) { + if (my_want_state_is_will(TELOPT_LINEMODE)) { + sendeof(); + return 0; + } + return 1; + } else if (c == termSuspChar) { + sendsusp(); + return(0); + } else if (c == termFlushChar) { + xmitAO(); /* Transmit Abort Output */ + return 0; + } else if (!MODE_LOCAL_CHARS(globalmode)) { + if (c == termKillChar) { + xmitEL(); + return 0; + } else if (c == termEraseChar) { + xmitEC(); /* Transmit Erase Character */ + return 0; + } + } + return 1; +} + + +/* + * Flush output to the terminal + */ + + void +TerminalFlushOutput() +{ +#ifdef TIOCFLUSH + (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); +#else + (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); +#endif +} + + void +TerminalSaveState() +{ +#ifndef USE_TERMIO + ioctl(0, TIOCGETP, (char *)&ottyb); + ioctl(0, TIOCGETC, (char *)&otc); + ioctl(0, TIOCGLTC, (char *)&oltc); + ioctl(0, TIOCLGET, (char *)&olmode); + + ntc = otc; + nltc = oltc; + nttyb = ottyb; + +#else /* USE_TERMIO */ + tcgetattr(0, &old_tc); + + new_tc = old_tc; + +#ifndef VDISCARD + termFlushChar = CONTROL('O'); +#endif +#ifndef VWERASE + termWerasChar = CONTROL('W'); +#endif +#ifndef VREPRINT + termRprntChar = CONTROL('R'); +#endif +#ifndef VLNEXT + termLiteralNextChar = CONTROL('V'); +#endif +#ifndef VSTART + termStartChar = CONTROL('Q'); +#endif +#ifndef VSTOP + termStopChar = CONTROL('S'); +#endif +#ifndef VSTATUS + termAytChar = CONTROL('T'); +#endif +#endif /* USE_TERMIO */ +} + + cc_t * +tcval(func) + register int func; +{ + switch(func) { + case SLC_IP: return(&termIntChar); + case SLC_ABORT: return(&termQuitChar); + case SLC_EOF: return(&termEofChar); + case SLC_EC: return(&termEraseChar); + case SLC_EL: return(&termKillChar); + case SLC_XON: return(&termStartChar); + case SLC_XOFF: return(&termStopChar); + case SLC_FORW1: return(&termForw1Char); +#ifdef USE_TERMIO + case SLC_FORW2: return(&termForw2Char); +# ifdef VDISCARD + case SLC_AO: return(&termFlushChar); +# endif +# ifdef VSUSP + case SLC_SUSP: return(&termSuspChar); +# endif +# ifdef VWERASE + case SLC_EW: return(&termWerasChar); +# endif +# ifdef VREPRINT + case SLC_RP: return(&termRprntChar); +# endif +# ifdef VLNEXT + case SLC_LNEXT: return(&termLiteralNextChar); +# endif +# ifdef VSTATUS + case SLC_AYT: return(&termAytChar); +# endif +#endif + + case SLC_SYNCH: + case SLC_BRK: + case SLC_EOR: + default: + return((cc_t *)0); + } +} + + void +TerminalDefaultChars() +{ +#ifndef USE_TERMIO + ntc = otc; + nltc = oltc; + nttyb.sg_kill = ottyb.sg_kill; + nttyb.sg_erase = ottyb.sg_erase; +#else /* USE_TERMIO */ + memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); +# ifndef VDISCARD + termFlushChar = CONTROL('O'); +# endif +# ifndef VWERASE + termWerasChar = CONTROL('W'); +# endif +# ifndef VREPRINT + termRprntChar = CONTROL('R'); +# endif +# ifndef VLNEXT + termLiteralNextChar = CONTROL('V'); +# endif +# ifndef VSTART + termStartChar = CONTROL('Q'); +# endif +# ifndef VSTOP + termStopChar = CONTROL('S'); +# endif +# ifndef VSTATUS + termAytChar = CONTROL('T'); +# endif +#endif /* USE_TERMIO */ +} + +#ifdef notdef +void +TerminalRestoreState() +{ +} +#endif + +/* + * TerminalNewMode - set up terminal to a specific mode. + * MODE_ECHO: do local terminal echo + * MODE_FLOW: do local flow control + * MODE_TRAPSIG: do local mapping to TELNET IAC sequences + * MODE_EDIT: do local line editing + * + * Command mode: + * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG + * local echo + * local editing + * local xon/xoff + * local signal mapping + * + * Linemode: + * local/no editing + * Both Linemode and Single Character mode: + * local/remote echo + * local/no xon/xoff + * local/no signal mapping + */ + + + void +TerminalNewMode(f) + register int f; +{ + static int prevmode = 0; +#ifndef USE_TERMIO + struct tchars tc; + struct ltchars ltc; + struct sgttyb sb; + int lmode; +#else /* USE_TERMIO */ + struct termio tmp_tc; +#endif /* USE_TERMIO */ + int onoff; + int old; + cc_t esc; + + globalmode = f&~MODE_FORCE; + if (prevmode == f) + return; + + /* + * Write any outstanding data before switching modes + * ttyflush() returns 0 only when there is no more data + * left to write out, it returns -1 if it couldn't do + * anything at all, otherwise it returns 1 + the number + * of characters left to write. +#ifndef USE_TERMIO + * We would really like ask the kernel to wait for the output + * to drain, like we can do with the TCSADRAIN, but we don't have + * that option. The only ioctl that waits for the output to + * drain, TIOCSETP, also flushes the input queue, which is NOT + * what we want (TIOCSETP is like TCSADFLUSH). +#endif + */ + old = ttyflush(SYNCHing|flushout); + if (old < 0 || old > 1) { +#ifdef USE_TERMIO + tcgetattr(tin, &tmp_tc); +#endif /* USE_TERMIO */ + do { + /* + * Wait for data to drain, then flush again. + */ +#ifdef USE_TERMIO + tcsetattr(tin, TCSADRAIN, &tmp_tc); +#endif /* USE_TERMIO */ + old = ttyflush(SYNCHing|flushout); + } while (old < 0 || old > 1); + } + + old = prevmode; + prevmode = f&~MODE_FORCE; +#ifndef USE_TERMIO + sb = nttyb; + tc = ntc; + ltc = nltc; + lmode = olmode; +#else + tmp_tc = new_tc; +#endif + + if (f&MODE_ECHO) { +#ifndef USE_TERMIO + sb.sg_flags |= ECHO; +#else + tmp_tc.c_lflag |= ECHO; + tmp_tc.c_oflag |= ONLCR; + if (crlf) + tmp_tc.c_iflag |= ICRNL; +#endif + } else { +#ifndef USE_TERMIO + sb.sg_flags &= ~ECHO; +#else + tmp_tc.c_lflag &= ~ECHO; + tmp_tc.c_oflag &= ~ONLCR; +# ifdef notdef + if (crlf) + tmp_tc.c_iflag &= ~ICRNL; +# endif +#endif + } + + if ((f&MODE_FLOW) == 0) { +#ifndef USE_TERMIO + tc.t_startc = _POSIX_VDISABLE; + tc.t_stopc = _POSIX_VDISABLE; +#else + tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ + } else { + if (restartany < 0) { + tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ + } else if (restartany > 0) { + tmp_tc.c_iflag |= IXOFF|IXON|IXANY; + } else { + tmp_tc.c_iflag |= IXOFF|IXON; + tmp_tc.c_iflag &= ~IXANY; + } +#endif + } + + if ((f&MODE_TRAPSIG) == 0) { +#ifndef USE_TERMIO + tc.t_intrc = _POSIX_VDISABLE; + tc.t_quitc = _POSIX_VDISABLE; + tc.t_eofc = _POSIX_VDISABLE; + ltc.t_suspc = _POSIX_VDISABLE; + ltc.t_dsuspc = _POSIX_VDISABLE; +#else + tmp_tc.c_lflag &= ~ISIG; +#endif + localchars = 0; + } else { +#ifdef USE_TERMIO + tmp_tc.c_lflag |= ISIG; +#endif + localchars = 1; + } + + if (f&MODE_EDIT) { +#ifndef USE_TERMIO + sb.sg_flags &= ~CBREAK; + sb.sg_flags |= CRMOD; +#else + tmp_tc.c_lflag |= ICANON; +#endif + } else { +#ifndef USE_TERMIO + sb.sg_flags |= CBREAK; + if (f&MODE_ECHO) + sb.sg_flags |= CRMOD; + else + sb.sg_flags &= ~CRMOD; +#else + tmp_tc.c_lflag &= ~ICANON; + tmp_tc.c_iflag &= ~ICRNL; + tmp_tc.c_cc[VMIN] = 1; + tmp_tc.c_cc[VTIME] = 0; +#endif + } + + if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { +#ifndef USE_TERMIO + ltc.t_lnextc = _POSIX_VDISABLE; +#else +# ifdef VLNEXT + tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); +# endif +#endif + } + + if (f&MODE_SOFT_TAB) { +#ifndef USE_TERMIO + sb.sg_flags |= XTABS; +#else +# ifdef OXTABS + tmp_tc.c_oflag |= OXTABS; +# endif +# ifdef TABDLY + tmp_tc.c_oflag &= ~TABDLY; + tmp_tc.c_oflag |= TAB3; +# endif +#endif + } else { +#ifndef USE_TERMIO + sb.sg_flags &= ~XTABS; +#else +# ifdef OXTABS + tmp_tc.c_oflag &= ~OXTABS; +# endif +# ifdef TABDLY + tmp_tc.c_oflag &= ~TABDLY; +# endif +#endif + } + + if (f&MODE_LIT_ECHO) { +#ifndef USE_TERMIO + lmode &= ~LCTLECH; +#else +# ifdef ECHOCTL + tmp_tc.c_lflag &= ~ECHOCTL; +# endif +#endif + } else { +#ifndef USE_TERMIO + lmode |= LCTLECH; +#else +# ifdef ECHOCTL + tmp_tc.c_lflag |= ECHOCTL; +# endif +#endif + } + + if (f == -1) { + onoff = 0; + } else { +#ifndef USE_TERMIO + if (f & MODE_OUTBIN) + lmode |= LLITOUT; + else + lmode &= ~LLITOUT; + + if (f & MODE_INBIN) + lmode |= LPASS8; + else + lmode &= ~LPASS8; +#else + if (f & MODE_INBIN) + tmp_tc.c_iflag &= ~ISTRIP; + else + tmp_tc.c_iflag |= ISTRIP; + if (f & MODE_OUTBIN) { + tmp_tc.c_cflag &= ~(CSIZE|PARENB); + tmp_tc.c_cflag |= CS8; + tmp_tc.c_oflag &= ~OPOST; + } else { + tmp_tc.c_cflag &= ~(CSIZE|PARENB); + tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); + tmp_tc.c_oflag |= OPOST; + } +#endif + onoff = 1; + } + + if (f != -1) { +#ifdef SIGTSTP + SIG_FUNC_RET susp(); +#endif /* SIGTSTP */ +#ifdef SIGINFO + SIG_FUNC_RET ayt(); +#endif + +#ifdef SIGTSTP + (void) signal(SIGTSTP, susp); +#endif /* SIGTSTP */ +#ifdef SIGINFO + (void) signal(SIGINFO, ayt); +#endif +#if defined(USE_TERMIO) && defined(NOKERNINFO) + tmp_tc.c_lflag |= NOKERNINFO; +#endif + /* + * We don't want to process ^Y here. It's just another + * character that we'll pass on to the back end. It has + * to process it because it will be processed when the + * user attempts to read it, not when we send it. + */ +#ifndef USE_TERMIO + ltc.t_dsuspc = _POSIX_VDISABLE; +#else +# ifdef VDSUSP + tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); +# endif +#endif +#ifdef USE_TERMIO + /* + * If the VEOL character is already set, then use VEOL2, + * otherwise use VEOL. + */ + esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; + if ((tmp_tc.c_cc[VEOL] != esc) +# ifdef VEOL2 + && (tmp_tc.c_cc[VEOL2] != esc) +# endif + ) { + if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) + tmp_tc.c_cc[VEOL] = esc; +# ifdef VEOL2 + else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) + tmp_tc.c_cc[VEOL2] = esc; +# endif + } +#else + if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) + tc.t_brkc = esc; +#endif + } else { +#ifdef SIGINFO + SIG_FUNC_RET ayt_status(); + + (void) signal(SIGINFO, ayt_status); +#endif +#ifdef SIGTSTP + (void) signal(SIGTSTP, SIG_DFL); + (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); +#endif /* SIGTSTP */ +#ifndef USE_TERMIO + ltc = oltc; + tc = otc; + sb = ottyb; + lmode = olmode; +#else + tmp_tc = old_tc; +#endif + } +#ifndef USE_TERMIO + ioctl(tin, TIOCLSET, (char *)&lmode); + ioctl(tin, TIOCSLTC, (char *)<c); + ioctl(tin, TIOCSETC, (char *)&tc); + ioctl(tin, TIOCSETN, (char *)&sb); +#else + if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) + tcsetattr(tin, TCSANOW, &tmp_tc); +#endif + +#if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) +# if !defined(sysV88) + ioctl(tin, FIONBIO, (char *)&onoff); + ioctl(tout, FIONBIO, (char *)&onoff); +# endif +#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ +#if defined(TN3270) + if (noasynchtty == 0) { + ioctl(tin, FIOASYNC, (char *)&onoff); + } +#endif /* defined(TN3270) */ + +} + +#ifndef B19200 +# define B19200 B9600 +#endif + +#ifndef B38400 +# define B38400 B19200 +#endif + +/* + * This code assumes that the values B0, B50, B75... + * are in ascending order. They do not have to be + * contiguous. + */ +struct termspeeds { + long speed; + long value; +} termspeeds[] = { + { 0, B0 }, { 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, B38400 } +}; + + void +TerminalSpeeds(ispeed, ospeed) + long *ispeed; + long *ospeed; +{ + register struct termspeeds *tp; + register long in, out; + + out = cfgetospeed(&old_tc); + in = cfgetispeed(&old_tc); + if (in == 0) + in = out; + + tp = termspeeds; + while ((tp->speed != -1) && (tp->value < in)) + tp++; + *ispeed = tp->speed; + + tp = termspeeds; + while ((tp->speed != -1) && (tp->value < out)) + tp++; + *ospeed = tp->speed; +} + + int +TerminalWindowSize(rows, cols) + long *rows, *cols; +{ +#ifdef TIOCGWINSZ + struct winsize ws; + + if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { + *rows = ws.ws_row; + *cols = ws.ws_col; + return 1; + } +#endif /* TIOCGWINSZ */ + return 0; +} + + int +NetClose(fd) + int fd; +{ + return close(fd); +} + + + void +NetNonblockingIO(fd, onoff) + int fd; + int onoff; +{ + ioctl(fd, FIONBIO, (char *)&onoff); +} + +#if defined(TN3270) + void +NetSigIO(fd, onoff) + int fd; + int onoff; +{ + ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ +} + + void +NetSetPgrp(fd) + int fd; +{ + int myPid; + + myPid = getpid(); + fcntl(fd, F_SETOWN, myPid); +} +#endif /*defined(TN3270)*/ + +/* + * Various signal handling routines. + */ + + /* ARGSUSED */ + SIG_FUNC_RET +deadpeer(sig) + int sig; +{ + setcommandmode(); + longjmp(peerdied, -1); +} + + /* ARGSUSED */ + SIG_FUNC_RET +intr(sig) + int sig; +{ + if (localchars) { + intp(); + return; + } + setcommandmode(); + longjmp(toplevel, -1); +} + + /* ARGSUSED */ + SIG_FUNC_RET +intr2(sig) + int sig; +{ + if (localchars) { +#ifdef KLUDGELINEMODE + if (kludgelinemode) + sendbrk(); + else +#endif + sendabort(); + return; + } +} + +#ifdef SIGTSTP + /* ARGSUSED */ + SIG_FUNC_RET +susp(sig) + int sig; +{ + if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) + return; + if (localchars) + sendsusp(); +} +#endif + +#ifdef SIGWINCH + /* ARGSUSED */ + SIG_FUNC_RET +sendwin(sig) + int sig; +{ + if (connected) { + sendnaws(); + } +} +#endif + +#ifdef SIGINFO + /* ARGSUSED */ + SIG_FUNC_RET +ayt(sig) + int sig; +{ + if (connected) + sendayt(); + else + ayt_status(); +} +#endif + + + void +sys_telnet_init() +{ + (void) signal(SIGINT, intr); + (void) signal(SIGQUIT, intr2); + (void) signal(SIGPIPE, deadpeer); +#ifdef SIGWINCH + (void) signal(SIGWINCH, sendwin); +#endif +#ifdef SIGTSTP + (void) signal(SIGTSTP, susp); +#endif +#ifdef SIGINFO + (void) signal(SIGINFO, ayt); +#endif + + setconnmode(0); + + NetNonblockingIO(net, 1); + +#if defined(TN3270) + if (noasynchnet == 0) { /* DBX can't handle! */ + NetSigIO(net, 1); + NetSetPgrp(net); + } +#endif /* defined(TN3270) */ + +#if defined(SO_OOBINLINE) + if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { + perror("SetSockOpt"); + } +#endif /* defined(SO_OOBINLINE) */ +} + +/* + * Process rings - + * + * This routine tries to fill up/empty our various rings. + * + * The parameter specifies whether this is a poll operation, + * or a block-until-something-happens operation. + * + * The return value is 1 if something happened, 0 if not. + */ + + int +process_rings(netin, netout, netex, ttyin, ttyout, poll) + int poll; /* If 0, then block until something to do */ +{ + register int c; + /* One wants to be a bit careful about setting returnValue + * to one, since a one implies we did some useful work, + * and therefore probably won't be called to block next + * time (TN3270 mode only). + */ + int returnValue = 0; + static struct timeval TimeValue = { 0 }; + + if (netout) { + FD_SET(net, &obits); + } + if (ttyout) { + FD_SET(tout, &obits); + } +#if defined(TN3270) + if (ttyin) { + FD_SET(tin, &ibits); + } +#else /* defined(TN3270) */ + if (ttyin) { + FD_SET(tin, &ibits); + } +#endif /* defined(TN3270) */ +#if defined(TN3270) + if (netin) { + FD_SET(net, &ibits); + } +# else /* !defined(TN3270) */ + if (netin) { + FD_SET(net, &ibits); + } +# endif /* !defined(TN3270) */ + if (netex) { + FD_SET(net, &xbits); + } + if ((c = select(16, &ibits, &obits, &xbits, + (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { + if (c == -1) { + /* + * we can get EINTR if we are in line mode, + * and the user does an escape (TSTP), or + * some other signal generator. + */ + if (errno == EINTR) { + return 0; + } +# if defined(TN3270) + /* + * we can get EBADF if we were in transparent + * mode, and the transcom process died. + */ + if (errno == EBADF) { + /* + * zero the bits (even though kernel does it) + * to make sure we are selecting on the right + * ones. + */ + FD_ZERO(&ibits); + FD_ZERO(&obits); + FD_ZERO(&xbits); + return 0; + } +# endif /* defined(TN3270) */ + /* I don't like this, does it ever happen? */ + printf("sleep(5) from telnet, after select\r\n"); + sleep(5); + } + return 0; + } + + /* + * Any urgent data? + */ + if (FD_ISSET(net, &xbits)) { + FD_CLR(net, &xbits); + SYNCHing = 1; + (void) ttyflush(1); /* flush already enqueued data */ + } + + /* + * Something to read from the network... + */ + if (FD_ISSET(net, &ibits)) { + int canread; + + FD_CLR(net, &ibits); + canread = ring_empty_consecutive(&netiring); +#if !defined(SO_OOBINLINE) + /* + * In 4.2 (and some early 4.3) systems, the + * OOB indication and data handling in the kernel + * is such that if two separate TCP Urgent requests + * come in, one byte of TCP data will be overlaid. + * This is fatal for Telnet, but we try to live + * with it. + * + * In addition, in 4.2 (and...), a special protocol + * is needed to pick up the TCP Urgent data in + * the correct sequence. + * + * What we do is: if we think we are in urgent + * mode, we look to see if we are "at the mark". + * If we are, we do an OOB receive. If we run + * this twice, we will do the OOB receive twice, + * but the second will fail, since the second + * time we were "at the mark", but there wasn't + * any data there (the kernel doesn't reset + * "at the mark" until we do a normal read). + * Once we've read the OOB data, we go ahead + * and do normal reads. + * + * There is also another problem, which is that + * since the OOB byte we read doesn't put us + * out of OOB state, and since that byte is most + * likely the TELNET DM (data mark), we would + * stay in the TELNET SYNCH (SYNCHing) state. + * So, clocks to the rescue. If we've "just" + * received a DM, then we test for the + * presence of OOB data when the receive OOB + * fails (and AFTER we did the normal mode read + * to clear "at the mark"). + */ + if (SYNCHing) { + int atmark; + static int bogus_oob = 0, first = 1; + + ioctl(net, SIOCATMARK, (char *)&atmark); + if (atmark) { + c = recv(net, netiring.supply, canread, MSG_OOB); + if ((c == -1) && (errno == EINVAL)) { + c = recv(net, netiring.supply, canread, 0); + if (clocks.didnetreceive < clocks.gotDM) { + SYNCHing = stilloob(net); + } + } else if (first && c > 0) { + /* + * Bogosity check. Systems based on 4.2BSD + * do not return an error if you do a second + * recv(MSG_OOB). So, we do one. If it + * succeeds and returns exactly the same + * data, then assume that we are running + * on a broken system and set the bogus_oob + * flag. (If the data was different, then + * we probably got some valid new data, so + * increment the count...) + */ + int i; + i = recv(net, netiring.supply + c, canread - c, MSG_OOB); + if (i == c && + bcmp(netiring.supply, netiring.supply + c, i) == 0) { + bogus_oob = 1; + first = 0; + } else if (i < 0) { + bogus_oob = 0; + first = 0; + } else + c += i; + } + if (bogus_oob && c > 0) { + int i; + /* + * Bogosity. We have to do the read + * to clear the atmark to get out of + * an infinate loop. + */ + i = read(net, netiring.supply + c, canread - c); + if (i > 0) + c += i; + } + } else { + c = recv(net, netiring.supply, canread, 0); + } + } else { + c = recv(net, netiring.supply, canread, 0); + } + settimer(didnetreceive); +#else /* !defined(SO_OOBINLINE) */ + c = recv(net, (char *)netiring.supply, canread, 0); +#endif /* !defined(SO_OOBINLINE) */ + if (c < 0 && errno == EWOULDBLOCK) { + c = 0; + } else if (c <= 0) { + return -1; + } + if (netdata) { + Dump('<', netiring.supply, c); + } + if (c) + ring_supplied(&netiring, c); + returnValue = 1; + } + + /* + * Something to read from the tty... + */ + if (FD_ISSET(tin, &ibits)) { + FD_CLR(tin, &ibits); + c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); + if (c < 0 && errno == EWOULDBLOCK) { + c = 0; + } else { + /* EOF detection for line mode!!!! */ + if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { + /* must be an EOF... */ + *ttyiring.supply = termEofChar; + c = 1; + } + if (c <= 0) { + return -1; + } + if (termdata) { + Dump('<', ttyiring.supply, c); + } + ring_supplied(&ttyiring, c); + } + returnValue = 1; /* did something useful */ + } + + if (FD_ISSET(net, &obits)) { + FD_CLR(net, &obits); + returnValue |= netflush(); + } + if (FD_ISSET(tout, &obits)) { + FD_CLR(tout, &obits); + returnValue |= (ttyflush(SYNCHing|flushout) > 0); + } + + return returnValue; +} diff --git a/usr.bin/telnet/telnet.1 b/usr.bin/telnet/telnet.1 new file mode 100644 index 0000000..27079d9 --- /dev/null +++ b/usr.bin/telnet/telnet.1 @@ -0,0 +1,1360 @@ +.\" Copyright (c) 1983, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)telnet.1 8.5 (Berkeley) 3/1/94 +.\" +.Dd March 1, 1994 +.Dt TELNET 1 +.Os BSD 4.2 +.Sh NAME +.Nm telnet +.Nd user interface to the +.Tn TELNET +protocol +.Sh SYNOPSIS +.Nm telnet +.Op Fl 8EFKLacdfrx +.Op Fl S Ar tos +.Op Fl X Ar authtype +.Op Fl e Ar escapechar +.Op Fl k Ar realm +.Op Fl l Ar user +.Op Fl n Ar tracefile +.Oo +.Ar host +.Op port +.Oc +.Sh DESCRIPTION +The +.Nm telnet +command +is used to communicate with another host using the +.Tn TELNET +protocol. +If +.Nm telnet +is invoked without the +.Ar host +argument, it enters command mode, +indicated by its prompt +.Pq Nm telnet\&> . +In this mode, it accepts and executes the commands listed below. +If it is invoked with arguments, it performs an +.Ic open +command with those arguments. +.Pp +Options: +.Bl -tag -width indent +.It Fl 8 +Specifies an 8-bit data path. This causes an attempt to +negotiate the +.Dv TELNET BINARY +option on both input and output. +.It Fl E +Stops any character from being recognized as an escape character. +.It Fl F +If Kerberos V5 authentication is being used, the +.Fl F +option allows the local credentials to be forwarded +to the remote system, including any credentials that +have already been forwarded into the local environment. +.It Fl K +Specifies no automatic login to the remote system. +.It Fl L +Specifies an 8-bit data path on output. This causes the +BINARY option to be negotiated on output. +.It Fl S Ar tos +Sets the IP type-of-service (TOS) option for the telnet +connection to the value +.Ar tos, +which can be a numeric TOS value +or, on systems that support it, a symbolic +TOS name found in the /etc/iptos file. +.It Fl X Ar atype +Disables the +.Ar atype +type of authentication. +.It Fl a +Attempt automatic login. +Currently, this sends the user name via the +.Ev USER +variable +of the +.Ev ENVIRON +option if supported by the remote system. +The name used is that of the current user as returned by +.Xr getlogin 2 +if it agrees with the current user ID, +otherwise it is the name associated with the user ID. +.It Fl c +Disables the reading of the user's +.Pa \&.telnetrc +file. (See the +.Ic toggle skiprc +command on this man page.) +.It Fl d +Sets the initial value of the +.Ic debug +toggle to +.Dv TRUE +.It Fl e Ar escape char +Sets the initial +.Nm +.Nm telnet +escape character to +.Ar escape char. +If +.Ar escape char +is omitted, then +there will be no escape character. +.It Fl f +If Kerberos V5 authentication is being used, the +.Fl f +option allows the local credentials to be forwarded to the remote system. +.It Fl k Ar realm +If Kerberos authentication is being used, the +.Fl k +option requests that telnet obtain tickets for the remote host in +realm realm instead of the remote host's realm, as determined +by +.Xr krb_realmofhost 3 . +.It Fl l Ar user +When connecting to the remote system, if the remote system +understands the +.Ev ENVIRON +option, then +.Ar user +will be sent to the remote system as the value for the variable USER. +This option implies the +.Fl a +option. +This option may also be used with the +.Ic open +command. +.It Fl n Ar tracefile +Opens +.Ar tracefile +for recording trace information. +See the +.Ic set tracefile +command below. +.It Fl r +Specifies a user interface similar to +.Xr rlogin 1 . +In this +mode, the escape character is set to the tilde (~) character, +unless modified by the -e option. +.It Fl x +Turns on encryption of the data stream if possible. This +option is not available outside of the United States and +Canada. +.It Ar host +Indicates the official name, an alias, or the Internet address +of a remote host. +.It Ar port +Indicates a port number (address of an application). If a number is +not specified, the default +.Nm telnet +port is used. +.El +.Pp +When in rlogin mode, a line of the form ~. disconnects from the +remote host; ~ is the telnet escape character. +Similarly, the line ~^Z suspends the telnet session. +The line ~^] escapes to the normal telnet escape prompt. +.Pp +Once a connection has been opened, +.Nm telnet +will attempt to enable the +.Dv TELNET LINEMODE +option. +If this fails, then +.Nm telnet +will revert to one of two input modes: +either \*(Lqcharacter at a time\*(Rq +or \*(Lqold line by line\*(Rq +depending on what the remote system supports. +.Pp +When +.Dv LINEMODE +is enabled, character processing is done on the +local system, under the control of the remote system. When input +editing or character echoing is to be disabled, the remote system +will relay that information. The remote system will also relay +changes to any special characters that happen on the remote +system, so that they can take effect on the local system. +.Pp +In \*(Lqcharacter at a time\*(Rq mode, most +text typed is immediately sent to the remote host for processing. +.Pp +In \*(Lqold line by line\*(Rq mode, all text is echoed locally, +and (normally) only completed lines are sent to the remote host. +The \*(Lqlocal echo character\*(Rq (initially \*(Lq^E\*(Rq) may be used +to turn off and on the local echo +(this would mostly be used to enter passwords +without the password being echoed). +.Pp +If the +.Dv LINEMODE +option is enabled, or if the +.Ic localchars +toggle is +.Dv TRUE +(the default for \*(Lqold line by line\*(Lq; see below), +the user's +.Ic quit , +.Ic intr , +and +.Ic flush +characters are trapped locally, and sent as +.Tn TELNET +protocol sequences to the remote side. +If +.Dv LINEMODE +has ever been enabled, then the user's +.Ic susp +and +.Ic eof +are also sent as +.Tn TELNET +protocol sequences, +and +.Ic quit +is sent as a +.Dv TELNET ABORT +instead of +.Dv BREAK +There are options (see +.Ic toggle +.Ic autoflush +and +.Ic toggle +.Ic autosynch +below) +which cause this action to flush subsequent output to the terminal +(until the remote host acknowledges the +.Tn TELNET +sequence) and flush previous terminal input +(in the case of +.Ic quit +and +.Ic intr ) . +.Pp +While connected to a remote host, +.Nm telnet +command mode may be entered by typing the +.Nm telnet +\*(Lqescape character\*(Rq (initially \*(Lq^]\*(Rq). +When in command mode, the normal terminal editing conventions are available. +.Pp +The following +.Nm telnet +commands are available. +Only enough of each command to uniquely identify it need be typed +(this is also true for arguments to the +.Ic mode , +.Ic set , +.Ic toggle , +.Ic unset , +.Ic slc , +.Ic environ , +and +.Ic display +commands). +.Pp +.Bl -tag -width "mode type" +.It Ic auth Ar argument ... +The auth command manipulates the information sent through the +.Dv TELNET AUTHENTICATE +option. Valid arguments for the +auth command are as follows: +.Bl -tag -width "disable type" +.It Ic disable Ar type +Disables the specified type of authentication. To +obtain a list of available types, use the +.Ic auth disable \&? +command. +.It Ic enable Ar type +Enables the specified type of authentication. To +obtain a list of available types, use the +.Ic auth enable \&? +command. +.It Ic status +Lists the current status of the various types of +authentication. +.El +.It Ic close +Close a +.Tn TELNET +session and return to command mode. +.It Ic display Ar argument ... +Displays all, or some, of the +.Ic set +and +.Ic toggle +values (see below). +.It Ic encrypt Ar argument ... +The encrypt command manipulates the information sent through the +.Dv TELNET ENCRYPT +option. +.Pp +Note: Because of export controls, the +.Dv TELNET ENCRYPT +option is not supported outside of the United States and Canada. +.Pp +Valid arguments for the encrypt command are as follows: +.Bl -tag -width Ar +.It Ic disable Ar type Ic [input|output] +Disables the specified type of encryption. If you +omit the input and output, both input and output +are disabled. To obtain a list of available +types, use the +.Ic encrypt disable \&? +command. +.It Ic enable Ar type Ic [input|output] +Enables the specified type of encryption. If you +omit input and output, both input and output are +enabled. To obtain a list of available types, use the +.Ic encrypt enable \&? +command. +.It Ic input +This is the same as the +.Ic encrypt start input +command. +.It Ic -input +This is the same as the +.Ic encrypt stop input +command. +.It Ic output +This is the same as the +.Ic encrypt start output +command. +.It Ic -output +This is the same as the +.Ic encrypt stop output +command. +.It Ic start Ic [input|output] +Attempts to start encryption. If you omit +.Ic input +and +.Ic output, +both input and output are enabled. To +obtain a list of available types, use the +.Ic encrypt enable \&? +command. +.It Ic status +Lists the current status of encryption. +.It Ic stop Ic [input|output] +Stops encryption. If you omit input and output, +encryption is on both input and output. +.It Ic type Ar type +Sets the default type of encryption to be used +with later +.Ic encrypt start +or +.Ic encrypt stop +commands. +.El +.It Ic environ Ar arguments... +The +.Ic environ +command is used to manipulate the +the variables that my be sent through the +.Dv TELNET ENVIRON +option. +The initial set of variables is taken from the users +environment, with only the +.Ev DISPLAY +and +.Ev PRINTER +variables being exported by default. +The +.Ev USER +variable is also exported if the +.Fl a +or +.Fl l +options are used. +.br +Valid arguments for the +.Ic environ +command are: +.Bl -tag -width Fl +.It Ic define Ar variable value +Define the variable +.Ar variable +to have a value of +.Ar value. +Any variables defined by this command are automatically exported. +The +.Ar value +may be enclosed in single or double quotes so +that tabs and spaces may be included. +.It Ic undefine Ar variable +Remove +.Ar variable +from the list of environment variables. +.It Ic export Ar variable +Mark the variable +.Ar variable +to be exported to the remote side. +.It Ic unexport Ar variable +Mark the variable +.Ar variable +to not be exported unless +explicitly asked for by the remote side. +.It Ic list +List the current set of environment variables. +Those marked with a +.Cm * +will be sent automatically, +other variables will only be sent if explicitly requested. +.It Ic \&? +Prints out help information for the +.Ic environ +command. +.El +.It Ic logout +Sends the +.Dv TELNET LOGOUT +option to the remote side. +This command is similar to a +.Ic close +command; however, if the remote side does not support the +.Dv LOGOUT +option, nothing happens. +If, however, the remote side does support the +.Dv LOGOUT +option, this command should cause the remote side to close the +.Tn TELNET +connection. +If the remote side also supports the concept of +suspending a user's session for later reattachment, +the logout argument indicates that you +should terminate the session immediately. +.It Ic mode Ar type +.Ar Type +is one of several options, depending on the state of the +.Tn TELNET +session. +The remote host is asked for permission to go into the requested mode. +If the remote host is capable of entering that mode, the requested +mode will be entered. +.Bl -tag -width Ar +.It Ic character +Disable the +.Dv TELNET LINEMODE +option, or, if the remote side does not understand the +.Dv LINEMODE +option, then enter \*(Lqcharacter at a time\*(Lq mode. +.It Ic line +Enable the +.Dv TELNET LINEMODE +option, or, if the remote side does not understand the +.Dv LINEMODE +option, then attempt to enter \*(Lqold-line-by-line\*(Lq mode. +.It Ic isig Pq Ic \-isig +Attempt to enable (disable) the +.Dv TRAPSIG +mode of the +.Dv LINEMODE +option. +This requires that the +.Dv LINEMODE +option be enabled. +.It Ic edit Pq Ic \-edit +Attempt to enable (disable) the +.Dv EDIT +mode of the +.Dv LINEMODE +option. +This requires that the +.Dv LINEMODE +option be enabled. +.It Ic softtabs Pq Ic \-softtabs +Attempt to enable (disable) the +.Dv SOFT_TAB +mode of the +.Dv LINEMODE +option. +This requires that the +.Dv LINEMODE +option be enabled. +.It Ic litecho Pq Ic \-litecho +Attempt to enable (disable) the +.Dv LIT_ECHO +mode of the +.Dv LINEMODE +option. +This requires that the +.Dv LINEMODE +option be enabled. +.It Ic \&? +Prints out help information for the +.Ic mode +command. +.El +.It Xo +.Ic open Ar host +.Oo Op Fl l +.Ar user +.Oc Ns Oo Fl +.Ar port Oc +.Xc +Open a connection to the named host. +If no port number +is specified, +.Nm telnet +will attempt to contact a +.Tn TELNET +server at the default port. +The host specification may be either a host name (see +.Xr hosts 5 ) +or an Internet address specified in the \*(Lqdot notation\*(Rq (see +.Xr inet 3 ) . +The +.Op Fl l +option may be used to specify the user name +to be passed to the remote system via the +.Ev ENVIRON +option. +When connecting to a non-standard port, +.Nm telnet +omits any automatic initiation of +.Tn TELNET +options. When the port number is preceded by a minus sign, +the initial option negotiation is done. +After establishing a connection, the file +.Pa \&.telnetrc +in the +users home directory is opened. Lines beginning with a # are +comment lines. Blank lines are ignored. Lines that begin +without white space are the start of a machine entry. The +first thing on the line is the name of the machine that is +being connected to. The rest of the line, and successive +lines that begin with white space are assumed to be +.Nm telnet +commands and are processed as if they had been typed +in manually to the +.Nm telnet +command prompt. +.It Ic quit +Close any open +.Tn TELNET +session and exit +.Nm telnet . +An end of file (in command mode) will also close a session and exit. +.It Ic send Ar arguments +Sends one or more special character sequences to the remote host. +The following are the arguments which may be specified +(more than one argument may be specified at a time): +.Pp +.Bl -tag -width escape +.It Ic abort +Sends the +.Dv TELNET ABORT +(Abort +processes) +sequence. +.It Ic ao +Sends the +.Dv TELNET AO +(Abort Output) sequence, which should cause the remote system to flush +all output +.Em from +the remote system +.Em to +the user's terminal. +.It Ic ayt +Sends the +.Dv TELNET AYT +(Are You There) +sequence, to which the remote system may or may not choose to respond. +.It Ic brk +Sends the +.Dv TELNET BRK +(Break) sequence, which may have significance to the remote +system. +.It Ic ec +Sends the +.Dv TELNET EC +(Erase Character) +sequence, which should cause the remote system to erase the last character +entered. +.It Ic el +Sends the +.Dv TELNET EL +(Erase Line) +sequence, which should cause the remote system to erase the line currently +being entered. +.It Ic eof +Sends the +.Dv TELNET EOF +(End Of File) +sequence. +.It Ic eor +Sends the +.Dv TELNET EOR +(End of Record) +sequence. +.It Ic escape +Sends the current +.Nm telnet +escape character (initially \*(Lq^\*(Rq). +.It Ic ga +Sends the +.Dv TELNET GA +(Go Ahead) +sequence, which likely has no significance to the remote system. +.It Ic getstatus +If the remote side supports the +.Dv TELNET STATUS +command, +.Ic getstatus +will send the subnegotiation to request that the server send +its current option status. +.It Ic ip +Sends the +.Dv TELNET IP +(Interrupt Process) sequence, which should cause the remote +system to abort the currently running process. +.It Ic nop +Sends the +.Dv TELNET NOP +(No OPeration) +sequence. +.It Ic susp +Sends the +.Dv TELNET SUSP +(SUSPend process) +sequence. +.It Ic synch +Sends the +.Dv TELNET SYNCH +sequence. +This sequence causes the remote system to discard all previously typed +(but not yet read) input. +This sequence is sent as +.Tn TCP +urgent +data (and may not work if the remote system is a +.Bx 4.2 +system -- if +it doesn't work, a lower case \*(Lqr\*(Rq may be echoed on the terminal). +.It Ic do Ar cmd +.It Ic dont Ar cmd +.It Ic will Ar cmd +.It Ic wont Ar cmd +Sends the +.Dv TELNET DO +.Ar cmd +sequence. +.Ar Cmd +can be either a decimal number between 0 and 255, +or a symbolic name for a specific +.Dv TELNET +command. +.Ar Cmd +can also be either +.Ic help +or +.Ic \&? +to print out help information, including +a list of known symbolic names. +.It Ic \&? +Prints out help information for the +.Ic send +command. +.El +.It Ic set Ar argument value +.It Ic unset Ar argument value +The +.Ic set +command will set any one of a number of +.Nm telnet +variables to a specific value or to +.Dv TRUE . +The special value +.Ic off +turns off the function associated with +the variable, this is equivalent to using the +.Ic unset +command. +The +.Ic unset +command will disable or set to +.Dv FALSE +any of the specified functions. +The values of variables may be interrogated with the +.Ic display +command. +The variables which may be set or unset, but not toggled, are +listed here. In addition, any of the variables for the +.Ic toggle +command may be explicitly set or unset using +the +.Ic set +and +.Ic unset +commands. +.Bl -tag -width escape +.It Ic ayt +If +.Tn TELNET +is in localchars mode, or +.Dv LINEMODE +is enabled, and the status character is typed, a +.Dv TELNET AYT +sequence (see +.Ic send ayt +preceding) is sent to the +remote host. The initial value for the "Are You There" +character is the terminal's status character. +.It Ic echo +This is the value (initially \*(Lq^E\*(Rq) which, when in +\*(Lqline by line\*(Rq mode, toggles between doing local echoing +of entered characters (for normal processing), and suppressing +echoing of entered characters (for entering, say, a password). +.It Ic eof +If +.Nm telnet +is operating in +.Dv LINEMODE +or \*(Lqold line by line\*(Rq mode, entering this character +as the first character on a line will cause this character to be +sent to the remote system. +The initial value of the eof character is taken to be the terminal's +.Ic eof +character. +.It Ic erase +If +.Nm telnet +is in +.Ic localchars +mode (see +.Ic toggle +.Ic localchars +below), +.Sy and +if +.Nm telnet +is operating in \*(Lqcharacter at a time\*(Rq mode, then when this +character is typed, a +.Dv TELNET EC +sequence (see +.Ic send +.Ic ec +above) +is sent to the remote system. +The initial value for the erase character is taken to be +the terminal's +.Ic erase +character. +.It Ic escape +This is the +.Nm telnet +escape character (initially \*(Lq^[\*(Rq) which causes entry +into +.Nm telnet +command mode (when connected to a remote system). +.It Ic flushoutput +If +.Nm telnet +is in +.Ic localchars +mode (see +.Ic toggle +.Ic localchars +below) +and the +.Ic flushoutput +character is typed, a +.Dv TELNET AO +sequence (see +.Ic send +.Ic ao +above) +is sent to the remote host. +The initial value for the flush character is taken to be +the terminal's +.Ic flush +character. +.It Ic forw1 +.It Ic forw2 +If +.Tn TELNET +is operating in +.Dv LINEMODE , +these are the +characters that, when typed, cause partial lines to be +forwarded to the remote system. The initial value for +the forwarding characters are taken from the terminal's +eol and eol2 characters. +.It Ic interrupt +If +.Nm telnet +is in +.Ic localchars +mode (see +.Ic toggle +.Ic localchars +below) +and the +.Ic interrupt +character is typed, a +.Dv TELNET IP +sequence (see +.Ic send +.Ic ip +above) +is sent to the remote host. +The initial value for the interrupt character is taken to be +the terminal's +.Ic intr +character. +.It Ic kill +If +.Nm telnet +is in +.Ic localchars +mode (see +.Ic toggle +.Ic localchars +below), +.Ic and +if +.Nm telnet +is operating in \*(Lqcharacter at a time\*(Rq mode, then when this +character is typed, a +.Dv TELNET EL +sequence (see +.Ic send +.Ic el +above) +is sent to the remote system. +The initial value for the kill character is taken to be +the terminal's +.Ic kill +character. +.It Ic lnext +If +.Nm telnet +is operating in +.Dv LINEMODE +or \*(Lqold line by line\*(Lq mode, then this character is taken to +be the terminal's +.Ic lnext +character. +The initial value for the lnext character is taken to be +the terminal's +.Ic lnext +character. +.It Ic quit +If +.Nm telnet +is in +.Ic localchars +mode (see +.Ic toggle +.Ic localchars +below) +and the +.Ic quit +character is typed, a +.Dv TELNET BRK +sequence (see +.Ic send +.Ic brk +above) +is sent to the remote host. +The initial value for the quit character is taken to be +the terminal's +.Ic quit +character. +.It Ic reprint +If +.Nm telnet +is operating in +.Dv LINEMODE +or \*(Lqold line by line\*(Lq mode, then this character is taken to +be the terminal's +.Ic reprint +character. +The initial value for the reprint character is taken to be +the terminal's +.Ic reprint +character. +.It Ic rlogin +This is the rlogin escape character. +If set, the normal +.Tn TELNET +escape character is ignored unless it is +preceded by this character at the beginning of a line. +This character, at the beginning of a line followed by +a "." closes the connection; when followed by a ^Z it +suspends the telnet command. The initial state is to +disable the rlogin escape character. +.It Ic start +If the +.Dv TELNET TOGGLE-FLOW-CONTROL +option has been enabled, +then this character is taken to +be the terminal's +.Ic start +character. +The initial value for the kill character is taken to be +the terminal's +.Ic start +character. +.It Ic stop +If the +.Dv TELNET TOGGLE-FLOW-CONTROL +option has been enabled, +then this character is taken to +be the terminal's +.Ic stop +character. +The initial value for the kill character is taken to be +the terminal's +.Ic stop +character. +.It Ic susp +If +.Nm telnet +is in +.Ic localchars +mode, or +.Dv LINEMODE +is enabled, and the +.Ic suspend +character is typed, a +.Dv TELNET SUSP +sequence (see +.Ic send +.Ic susp +above) +is sent to the remote host. +The initial value for the suspend character is taken to be +the terminal's +.Ic suspend +character. +.It Ic tracefile +This is the file to which the output, caused by +.Ic netdata +or +.Ic option +tracing being +.Dv TRUE , +will be written. If it is set to +.Dq Fl , +then tracing information will be written to standard output (the default). +.It Ic worderase +If +.Nm telnet +is operating in +.Dv LINEMODE +or \*(Lqold line by line\*(Lq mode, then this character is taken to +be the terminal's +.Ic worderase +character. +The initial value for the worderase character is taken to be +the terminal's +.Ic worderase +character. +.It Ic \&? +Displays the legal +.Ic set +.Pq Ic unset +commands. +.El +.It Ic slc Ar state +The +.Ic slc +command (Set Local Characters) is used to set +or change the state of the the special +characters when the +.Dv TELNET LINEMODE +option has +been enabled. Special characters are characters that get +mapped to +.Tn TELNET +commands sequences (like +.Ic ip +or +.Ic quit ) +or line editing characters (like +.Ic erase +and +.Ic kill ) . +By default, the local special characters are exported. +.Bl -tag -width Fl +.It Ic check +Verify the current settings for the current special characters. +The remote side is requested to send all the current special +character settings, and if there are any discrepancies with +the local side, the local side will switch to the remote value. +.It Ic export +Switch to the local defaults for the special characters. The +local default characters are those of the local terminal at +the time when +.Nm telnet +was started. +.It Ic import +Switch to the remote defaults for the special characters. +The remote default characters are those of the remote system +at the time when the +.Tn TELNET +connection was established. +.It Ic \&? +Prints out help information for the +.Ic slc +command. +.El +.It Ic status +Show the current status of +.Nm telnet . +This includes the peer one is connected to, as well +as the current mode. +.It Ic toggle Ar arguments ... +Toggle (between +.Dv TRUE +and +.Dv FALSE ) +various flags that control how +.Nm telnet +responds to events. +These flags may be set explicitly to +.Dv TRUE +or +.Dv FALSE +using the +.Ic set +and +.Ic unset +commands listed above. +More than one argument may be specified. +The state of these flags may be interrogated with the +.Ic display +command. +Valid arguments are: +.Bl -tag -width Ar +.It Ic authdebug +Turns on debugging information for the authentication code. +.It Ic autoflush +If +.Ic autoflush +and +.Ic localchars +are both +.Dv TRUE , +then when the +.Ic ao , +or +.Ic quit +characters are recognized (and transformed into +.Tn TELNET +sequences; see +.Ic set +above for details), +.Nm telnet +refuses to display any data on the user's terminal +until the remote system acknowledges (via a +.Dv TELNET TIMING MARK +option) +that it has processed those +.Tn TELNET +sequences. +The initial value for this toggle is +.Dv TRUE +if the terminal user had not +done an "stty noflsh", otherwise +.Dv FALSE +(see +.Xr stty 1 ) . +.It Ic autodecrypt +When the +.Dv TELNET ENCRYPT +option is negotiated, by +default the actual encryption (decryption) of the data +stream does not start automatically. The autoencrypt +(autodecrypt) command states that encryption of the +output (input) stream should be enabled as soon as +possible. +.Pp +Note: Because of export controls, the +.Dv TELNET ENCRYPT +option is not supported outside the United States and Canada. +.It Ic autologin +If the remote side supports the +.Dv TELNET AUTHENTICATION +option +.Tn TELNET +attempts to use it to perform automatic authentication. If the +.Dv AUTHENTICATION +option is not supported, the user's login +name are propagated through the +.Dv TELNET ENVIRON +option. +This command is the same as specifying +.Ar a +option on the +.Ic open +command. +.It Ic autosynch +If +.Ic autosynch +and +.Ic localchars +are both +.Dv TRUE , +then when either the +.Ic intr +or +.Ic quit +characters is typed (see +.Ic set +above for descriptions of the +.Ic intr +and +.Ic quit +characters), the resulting +.Tn TELNET +sequence sent is followed by the +.Dv TELNET SYNCH +sequence. +This procedure +.Ic should +cause the remote system to begin throwing away all previously +typed input until both of the +.Tn TELNET +sequences have been read and acted upon. +The initial value of this toggle is +.Dv FALSE . +.It Ic binary +Enable or disable the +.Dv TELNET BINARY +option on both input and output. +.It Ic inbinary +Enable or disable the +.Dv TELNET BINARY +option on input. +.It Ic outbinary +Enable or disable the +.Dv TELNET BINARY +option on output. +.It Ic crlf +If this is +.Dv TRUE , +then carriage returns will be sent as +.Li . +If this is +.Dv FALSE , +then carriage returns will be send as +.Li . +The initial value for this toggle is +.Dv FALSE . +.It Ic crmod +Toggle carriage return mode. +When this mode is enabled, most carriage return characters received from +the remote host will be mapped into a carriage return followed by +a line feed. +This mode does not affect those characters typed by the user, only +those received from the remote host. +This mode is not very useful unless the remote host +only sends carriage return, but never line feed. +The initial value for this toggle is +.Dv FALSE . +.It Ic debug +Toggles socket level debugging (useful only to the +.Ic super user ) . +The initial value for this toggle is +.Dv FALSE . +.It Ic encdebug +Turns on debugging information for the encryption code. +.It Ic localchars +If this is +.Dv TRUE , +then the +.Ic flush , +.Ic interrupt , +.Ic quit , +.Ic erase , +and +.Ic kill +characters (see +.Ic set +above) are recognized locally, and transformed into (hopefully) appropriate +.Tn TELNET +control sequences +(respectively +.Ic ao , +.Ic ip , +.Ic brk , +.Ic ec , +and +.Ic el ; +see +.Ic send +above). +The initial value for this toggle is +.Dv TRUE +in \*(Lqold line by line\*(Rq mode, +and +.Dv FALSE +in \*(Lqcharacter at a time\*(Rq mode. +When the +.Dv LINEMODE +option is enabled, the value of +.Ic localchars +is ignored, and assumed to always be +.Dv TRUE . +If +.Dv LINEMODE +has ever been enabled, then +.Ic quit +is sent as +.Ic abort , +and +.Ic eof and +.B suspend +are sent as +.Ic eof and +.Ic susp , +see +.Ic send +above). +.It Ic netdata +Toggles the display of all network data (in hexadecimal format). +The initial value for this toggle is +.Dv FALSE . +.It Ic options +Toggles the display of some internal +.Nm telnet +protocol processing (having to do with +.Tn TELNET +options). +The initial value for this toggle is +.Dv FALSE . +.It Ic prettydump +When the +.Ic netdata +toggle is enabled, if +.Ic prettydump +is enabled the output from the +.Ic netdata +command will be formatted in a more user readable format. +Spaces are put between each character in the output, and the +beginning of any +.Tn TELNET +escape sequence is preceded by a '*' to aid in locating them. +.It Ic skiprc +When the skiprc toggle is +.Dv TRUE , +.Tn TELNET +skips the reading of the +.Pa \&.telnetrc +file in the users home +directory when connections are opened. The initial +value for this toggle is +.Dv FALSE. +.It Ic termdata +Toggles the display of all terminal data (in hexadecimal format). +The initial value for this toggle is +.Dv FALSE . +.It Ic verbose_encrypt +When the +.Ic verbose_encrypt +toggle is +.Dv TRUE , +.Tn TELNET +prints out a message each time encryption is enabled or +disabled. The initial value for this toggle is +.Dv FALSE. +Note: Because of export controls, data encryption +is not supported outside of the United States and Canada. +.It Ic \&? +Displays the legal +.Ic toggle +commands. +.El +.It Ic z +Suspend +.Nm telnet . +This command only works when the user is using the +.Xr csh 1 . +.It Ic \&! Op Ar command +Execute a single command in a subshell on the local +system. If +.Ic command +is omitted, then an interactive +subshell is invoked. +.It Ic \&? Op Ar command +Get help. With no arguments, +.Nm telnet +prints a help summary. +If a command is specified, +.Nm telnet +will print the help information for just that command. +.El +.Sh ENVIRONMENT +.Nm Telnet +uses at least the +.Ev HOME , +.Ev SHELL , +.Ev DISPLAY , +and +.Ev TERM +environment variables. +Other environment variables may be propagated +to the other side via the +.Dv TELNET ENVIRON +option. +.Sh FILES +.Bl -tag -width ~/.telnetrc -compact +.It Pa ~/.telnetrc +user customized telnet startup values +.El +.Sh HISTORY +The +.Nm Telnet +command appeared in +.Bx 4.2 . +.Sh NOTES +.Pp +On some remote systems, echo has to be turned off manually when in +\*(Lqold line by line\*(Rq mode. +.Pp +In \*(Lqold line by line\*(Rq mode or +.Dv LINEMODE +the terminal's +.Ic eof +character is only recognized (and sent to the remote system) +when it is the first character on a line. diff --git a/usr.bin/telnet/telnet.c b/usr.bin/telnet/telnet.c new file mode 100644 index 0000000..97f63e6 --- /dev/null +++ b/usr.bin/telnet/telnet.c @@ -0,0 +1,2650 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)telnet.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +#include + +#if defined(unix) +#include +/* By the way, we need to include curses.h before telnet.h since, + * among other things, telnet.h #defines 'DO', which is a variable + * declared in curses.h. + */ +#endif /* defined(unix) */ + +#include + +#include + +#include "ring.h" + +#include "defines.h" +#include "externs.h" +#include "types.h" +#include "general.h" + + +#define strip(x) ((x)&0x7f) + +static unsigned char subbuffer[SUBBUFSIZE], + *subpointer, *subend; /* buffer for sub-options */ +#define SB_CLEAR() subpointer = subbuffer; +#define SB_TERM() { subend = subpointer; SB_CLEAR(); } +#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ + *subpointer++ = (c); \ + } + +#define SB_GET() ((*subpointer++)&0xff) +#define SB_PEEK() ((*subpointer)&0xff) +#define SB_EOF() (subpointer >= subend) +#define SB_LEN() (subend - subpointer) + +char options[256]; /* The combined options */ +char do_dont_resp[256]; +char will_wont_resp[256]; + +int + eight = 0, + autologin = 0, /* Autologin anyone? */ + skiprc = 0, + connected, + showoptions, + In3270, /* Are we in 3270 mode? */ + ISend, /* trying to send network data in */ + debug = 0, + crmod, + netdata, /* Print out network data flow */ + crlf, /* Should '\r' be mapped to (or )? */ +#if defined(TN3270) + noasynchtty = 0,/* User specified "-noasynch" on command line */ + noasynchnet = 0,/* User specified "-noasynch" on command line */ + askedSGA = 0, /* We have talked about suppress go ahead */ +#endif /* defined(TN3270) */ + telnetport, + SYNCHing, /* we are in TELNET SYNCH mode */ + flushout, /* flush output */ + autoflush = 0, /* flush output when interrupting? */ + autosynch, /* send interrupt characters with SYNCH? */ + localflow, /* we handle flow control locally */ + restartany, /* if flow control enabled, restart on any character */ + localchars, /* we recognize interrupt/quit */ + donelclchars, /* the user has set "localchars" */ + donebinarytoggle, /* the user has put us in binary */ + dontlecho, /* do we suppress local echoing right now? */ + globalmode; + +char *prompt = 0; + +cc_t escape; +cc_t rlogin; +#ifdef KLUDGELINEMODE +cc_t echoc; +#endif + +/* + * Telnet receiver states for fsm + */ +#define TS_DATA 0 +#define TS_IAC 1 +#define TS_WILL 2 +#define TS_WONT 3 +#define TS_DO 4 +#define TS_DONT 5 +#define TS_CR 6 +#define TS_SB 7 /* sub-option collection */ +#define TS_SE 8 /* looking for sub-option end */ + +static int telrcv_state; +#ifdef OLD_ENVIRON +unsigned char telopt_environ = TELOPT_NEW_ENVIRON; +#else +# define telopt_environ TELOPT_NEW_ENVIRON +#endif + +jmp_buf toplevel = { 0 }; +jmp_buf peerdied; + +int flushline; +int linemode; + +#ifdef KLUDGELINEMODE +int kludgelinemode = 1; +#endif + +/* + * The following are some clocks used to decide how to interpret + * the relationship between various variables. + */ + +Clocks clocks; + +#ifdef notdef +Modelist modelist[] = { + { "telnet command mode", COMMAND_LINE }, + { "character-at-a-time mode", 0 }, + { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, + { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, + { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, + { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, + { "3270 mode", 0 }, +}; +#endif + + +/* + * Initialize telnet environment. + */ + + void +init_telnet() +{ + env_init(); + + SB_CLEAR(); + ClearArray(options); + + connected = In3270 = ISend = localflow = donebinarytoggle = 0; +#if defined(AUTHENTICATION) || defined(ENCRYPTION) + auth_encrypt_connect(connected); +#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ + restartany = -1; + + SYNCHing = 0; + + /* Don't change NetTrace */ + + escape = CONTROL(']'); + rlogin = _POSIX_VDISABLE; +#ifdef KLUDGELINEMODE + echoc = CONTROL('E'); +#endif + + flushline = 1; + telrcv_state = TS_DATA; +} + + +#ifdef notdef +#include + + /*VARARGS*/ + static void +printring(va_alist) + va_dcl +{ + va_list ap; + char buffer[100]; /* where things go */ + char *ptr; + char *format; + char *string; + Ring *ring; + int i; + + va_start(ap); + + ring = va_arg(ap, Ring *); + format = va_arg(ap, char *); + ptr = buffer; + + while ((i = *format++) != 0) { + if (i == '%') { + i = *format++; + switch (i) { + case 'c': + *ptr++ = va_arg(ap, int); + break; + case 's': + string = va_arg(ap, char *); + ring_supply_data(ring, buffer, ptr-buffer); + ring_supply_data(ring, string, strlen(string)); + ptr = buffer; + break; + case 0: + ExitString("printring: trailing %%.\n", 1); + /*NOTREACHED*/ + default: + ExitString("printring: unknown format character.\n", 1); + /*NOTREACHED*/ + } + } else { + *ptr++ = i; + } + } + ring_supply_data(ring, buffer, ptr-buffer); +} +#endif + +/* + * These routines are in charge of sending option negotiations + * to the other side. + * + * The basic idea is that we send the negotiation if either side + * is in disagreement as to what the current state should be. + */ + + void +send_do(c, init) + register int c, init; +{ + if (init) { + if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || + my_want_state_is_do(c)) + return; + set_my_want_state_do(c); + do_dont_resp[c]++; + } + NET2ADD(IAC, DO); + NETADD(c); + printoption("SENT", DO, c); +} + + void +send_dont(c, init) + register int c, init; +{ + if (init) { + if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || + my_want_state_is_dont(c)) + return; + set_my_want_state_dont(c); + do_dont_resp[c]++; + } + NET2ADD(IAC, DONT); + NETADD(c); + printoption("SENT", DONT, c); +} + + void +send_will(c, init) + register int c, init; +{ + if (init) { + if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || + my_want_state_is_will(c)) + return; + set_my_want_state_will(c); + will_wont_resp[c]++; + } + NET2ADD(IAC, WILL); + NETADD(c); + printoption("SENT", WILL, c); +} + + void +send_wont(c, init) + register int c, init; +{ + if (init) { + if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || + my_want_state_is_wont(c)) + return; + set_my_want_state_wont(c); + will_wont_resp[c]++; + } + NET2ADD(IAC, WONT); + NETADD(c); + printoption("SENT", WONT, c); +} + + + void +willoption(option) + int option; +{ + int new_state_ok = 0; + + if (do_dont_resp[option]) { + --do_dont_resp[option]; + if (do_dont_resp[option] && my_state_is_do(option)) + --do_dont_resp[option]; + } + + if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { + + switch (option) { + + case TELOPT_ECHO: +# if defined(TN3270) + /* + * The following is a pain in the rear-end. + * Various IBM servers (some versions of Wiscnet, + * possibly Fibronics/Spartacus, and who knows who + * else) will NOT allow us to send "DO SGA" too early + * in the setup proceedings. On the other hand, + * 4.2 servers (telnetd) won't set SGA correctly. + * So, we are stuck. Empirically (but, based on + * a VERY small sample), the IBM servers don't send + * out anything about ECHO, so we postpone our sending + * "DO SGA" until we see "WILL ECHO" (which 4.2 servers + * DO send). + */ + { + if (askedSGA == 0) { + askedSGA = 1; + if (my_want_state_is_dont(TELOPT_SGA)) + send_do(TELOPT_SGA, 1); + } + } + /* Fall through */ + case TELOPT_EOR: +#endif /* defined(TN3270) */ + case TELOPT_BINARY: + case TELOPT_SGA: + settimer(modenegotiated); + /* FALL THROUGH */ + case TELOPT_STATUS: +#if defined(AUTHENTICATION) + case TELOPT_AUTHENTICATION: +#endif +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: +#endif /* ENCRYPTION */ + new_state_ok = 1; + break; + + case TELOPT_TM: + if (flushout) + flushout = 0; + /* + * Special case for TM. If we get back a WILL, + * pretend we got back a WONT. + */ + set_my_want_state_dont(option); + set_my_state_dont(option); + return; /* Never reply to TM will's/wont's */ + + case TELOPT_LINEMODE: + default: + break; + } + + if (new_state_ok) { + set_my_want_state_do(option); + send_do(option, 0); + setconnmode(0); /* possibly set new tty mode */ + } else { + do_dont_resp[option]++; + send_dont(option, 0); + } + } + set_my_state_do(option); +#ifdef ENCRYPTION + if (option == TELOPT_ENCRYPT) + encrypt_send_support(); +#endif /* ENCRYPTION */ +} + + void +wontoption(option) + int option; +{ + if (do_dont_resp[option]) { + --do_dont_resp[option]; + if (do_dont_resp[option] && my_state_is_dont(option)) + --do_dont_resp[option]; + } + + if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { + + switch (option) { + +#ifdef KLUDGELINEMODE + case TELOPT_SGA: + if (!kludgelinemode) + break; + /* FALL THROUGH */ +#endif + case TELOPT_ECHO: + settimer(modenegotiated); + break; + + case TELOPT_TM: + if (flushout) + flushout = 0; + set_my_want_state_dont(option); + set_my_state_dont(option); + return; /* Never reply to TM will's/wont's */ + + default: + break; + } + set_my_want_state_dont(option); + if (my_state_is_do(option)) + send_dont(option, 0); + setconnmode(0); /* Set new tty mode */ + } else if (option == TELOPT_TM) { + /* + * Special case for TM. + */ + if (flushout) + flushout = 0; + set_my_want_state_dont(option); + } + set_my_state_dont(option); +} + + static void +dooption(option) + int option; +{ + int new_state_ok = 0; + + if (will_wont_resp[option]) { + --will_wont_resp[option]; + if (will_wont_resp[option] && my_state_is_will(option)) + --will_wont_resp[option]; + } + + if (will_wont_resp[option] == 0) { + if (my_want_state_is_wont(option)) { + + switch (option) { + + case TELOPT_TM: + /* + * Special case for TM. We send a WILL, but pretend + * we sent WONT. + */ + send_will(option, 0); + set_my_want_state_wont(TELOPT_TM); + set_my_state_wont(TELOPT_TM); + return; + +# if defined(TN3270) + case TELOPT_EOR: /* end of record */ +# endif /* defined(TN3270) */ + case TELOPT_BINARY: /* binary mode */ + case TELOPT_NAWS: /* window size */ + case TELOPT_TSPEED: /* terminal speed */ + case TELOPT_LFLOW: /* local flow control */ + case TELOPT_TTYPE: /* terminal type option */ + case TELOPT_SGA: /* no big deal */ +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: /* encryption variable option */ +#endif /* ENCRYPTION */ + new_state_ok = 1; + break; + + case TELOPT_NEW_ENVIRON: /* New environment variable option */ +#ifdef OLD_ENVIRON + if (my_state_is_will(TELOPT_OLD_ENVIRON)) + send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ + goto env_common; + case TELOPT_OLD_ENVIRON: /* Old environment variable option */ + if (my_state_is_will(TELOPT_NEW_ENVIRON)) + break; /* Don't enable if new one is in use! */ + env_common: + telopt_environ = option; +#endif + new_state_ok = 1; + break; + +#if defined(AUTHENTICATION) + case TELOPT_AUTHENTICATION: + if (autologin) + new_state_ok = 1; + break; +#endif + + case TELOPT_XDISPLOC: /* X Display location */ + if (env_getvalue((unsigned char *)"DISPLAY")) + new_state_ok = 1; + break; + + case TELOPT_LINEMODE: +#ifdef KLUDGELINEMODE + kludgelinemode = 0; + send_do(TELOPT_SGA, 1); +#endif + set_my_want_state_will(TELOPT_LINEMODE); + send_will(option, 0); + set_my_state_will(TELOPT_LINEMODE); + slc_init(); + return; + + case TELOPT_ECHO: /* We're never going to echo... */ + default: + break; + } + + if (new_state_ok) { + set_my_want_state_will(option); + send_will(option, 0); + setconnmode(0); /* Set new tty mode */ + } else { + will_wont_resp[option]++; + send_wont(option, 0); + } + } else { + /* + * Handle options that need more things done after the + * other side has acknowledged the option. + */ + switch (option) { + case TELOPT_LINEMODE: +#ifdef KLUDGELINEMODE + kludgelinemode = 0; + send_do(TELOPT_SGA, 1); +#endif + set_my_state_will(option); + slc_init(); + send_do(TELOPT_SGA, 0); + return; + } + } + } + set_my_state_will(option); +} + + static void +dontoption(option) + int option; +{ + + if (will_wont_resp[option]) { + --will_wont_resp[option]; + if (will_wont_resp[option] && my_state_is_wont(option)) + --will_wont_resp[option]; + } + + if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { + switch (option) { + case TELOPT_LINEMODE: + linemode = 0; /* put us back to the default state */ + break; +#ifdef OLD_ENVIRON + case TELOPT_NEW_ENVIRON: + /* + * The new environ option wasn't recognized, try + * the old one. + */ + send_will(TELOPT_OLD_ENVIRON, 1); + telopt_environ = TELOPT_OLD_ENVIRON; + break; +#endif + } + /* we always accept a DONT */ + set_my_want_state_wont(option); + if (my_state_is_will(option)) + send_wont(option, 0); + setconnmode(0); /* Set new tty mode */ + } + set_my_state_wont(option); +} + +/* + * Given a buffer returned by tgetent(), this routine will turn + * the pipe seperated list of names in the buffer into an array + * of pointers to null terminated names. We toss out any bad, + * duplicate, or verbose names (names with spaces). + */ + +static char *name_unknown = "UNKNOWN"; +static char *unknown[] = { 0, 0 }; + + char ** +mklist(buf, name) + char *buf, *name; +{ + register int n; + register char c, *cp, **argvp, *cp2, **argv, **avt; + + if (name) { + if (strlen(name) > 40) { + name = 0; + unknown[0] = name_unknown; + } else { + unknown[0] = name; + upcase(name); + } + } else + unknown[0] = name_unknown; + /* + * Count up the number of names. + */ + for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { + if (*cp == '|') + n++; + } + /* + * Allocate an array to put the name pointers into + */ + argv = (char **)malloc((n+3)*sizeof(char *)); + if (argv == 0) + return(unknown); + + /* + * Fill up the array of pointers to names. + */ + *argv = 0; + argvp = argv+1; + n = 0; + for (cp = cp2 = buf; (c = *cp); cp++) { + if (c == '|' || c == ':') { + *cp++ = '\0'; + /* + * Skip entries that have spaces or are over 40 + * characters long. If this is our environment + * name, then put it up front. Otherwise, as + * long as this is not a duplicate name (case + * insensitive) add it to the list. + */ + if (n || (cp - cp2 > 41)) + ; + else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) + *argv = cp2; + else if (is_unique(cp2, argv+1, argvp)) + *argvp++ = cp2; + if (c == ':') + break; + /* + * Skip multiple delimiters. Reset cp2 to + * the beginning of the next name. Reset n, + * the flag for names with spaces. + */ + while ((c = *cp) == '|') + cp++; + cp2 = cp; + n = 0; + } + /* + * Skip entries with spaces or non-ascii values. + * Convert lower case letters to upper case. + */ + if ((c == ' ') || !isascii(c)) + n = 1; + else if (islower(c)) + *cp = toupper(c); + } + + /* + * Check for an old V6 2 character name. If the second + * name points to the beginning of the buffer, and is + * only 2 characters long, move it to the end of the array. + */ + if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { + --argvp; + for (avt = &argv[1]; avt < argvp; avt++) + *avt = *(avt+1); + *argvp++ = buf; + } + + /* + * Duplicate last name, for TTYPE option, and null + * terminate the array. If we didn't find a match on + * our terminal name, put that name at the beginning. + */ + cp = *(argvp-1); + *argvp++ = cp; + *argvp = 0; + + if (*argv == 0) { + if (name) + *argv = name; + else { + --argvp; + for (avt = argv; avt < argvp; avt++) + *avt = *(avt+1); + } + } + if (*argv) + return(argv); + else + return(unknown); +} + + int +is_unique(name, as, ae) + register char *name, **as, **ae; +{ + register char **ap; + register int n; + + n = strlen(name) + 1; + for (ap = as; ap < ae; ap++) + if (strncasecmp(*ap, name, n) == 0) + return(0); + return (1); +} + +#ifdef TERMCAP +char termbuf[1024]; + + /*ARGSUSED*/ + int +setupterm(tname, fd, errp) + char *tname; + int fd, *errp; +{ + if (tgetent(termbuf, tname) == 1) { + termbuf[1023] = '\0'; + if (errp) + *errp = 1; + return(0); + } + if (errp) + *errp = 0; + return(-1); +} +#else +#define termbuf ttytype +extern char ttytype[]; +#endif + +int resettermname = 1; + + char * +gettermname() +{ + char *tname; + static char **tnamep = 0; + static char **next; + int err; + + if (resettermname) { + resettermname = 0; + if (tnamep && tnamep != unknown) + free(tnamep); + if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && + (setupterm(tname, 1, &err) == 0)) { + tnamep = mklist(termbuf, tname); + } else { + if (tname && (strlen(tname) <= 40)) { + unknown[0] = tname; + upcase(tname); + } else + unknown[0] = name_unknown; + tnamep = unknown; + } + next = tnamep; + } + if (*next == 0) + next = tnamep; + return(*next++); +} +/* + * suboption() + * + * Look at the sub-option buffer, and try to be helpful to the other + * side. + * + * Currently we recognize: + * + * Terminal type, send request. + * Terminal speed (send request). + * Local flow control (is request). + * Linemode + */ + + static void +suboption() +{ + unsigned char subchar; + + printsub('<', subbuffer, SB_LEN()+2); + switch (subchar = SB_GET()) { + case TELOPT_TTYPE: + if (my_want_state_is_wont(TELOPT_TTYPE)) + return; + if (SB_EOF() || SB_GET() != TELQUAL_SEND) { + return; + } else { + char *name; + unsigned char temp[50]; + int len; + +#if defined(TN3270) + if (tn3270_ttype()) { + return; + } +#endif /* defined(TN3270) */ + name = gettermname(); + len = strlen(name) + 4 + 2; + if (len < NETROOM()) { + sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, + TELQUAL_IS, name, IAC, SE); + ring_supply_data(&netoring, temp, len); + printsub('>', &temp[2], len-2); + } else { + ExitString("No room in buffer for terminal type.\n", 1); + /*NOTREACHED*/ + } + } + break; + case TELOPT_TSPEED: + if (my_want_state_is_wont(TELOPT_TSPEED)) + return; + if (SB_EOF()) + return; + if (SB_GET() == TELQUAL_SEND) { + long ospeed, ispeed; + unsigned char temp[50]; + int len; + + TerminalSpeeds(&ispeed, &ospeed); + + sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, + TELQUAL_IS, ospeed, ispeed, IAC, SE); + len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ + + if (len < NETROOM()) { + ring_supply_data(&netoring, temp, len); + printsub('>', temp+2, len - 2); + } +/*@*/ else printf("lm_will: not enough room in buffer\n"); + } + break; + case TELOPT_LFLOW: + if (my_want_state_is_wont(TELOPT_LFLOW)) + return; + if (SB_EOF()) + return; + switch(SB_GET()) { + case LFLOW_RESTART_ANY: + restartany = 1; + break; + case LFLOW_RESTART_XON: + restartany = 0; + break; + case LFLOW_ON: + localflow = 1; + break; + case LFLOW_OFF: + localflow = 0; + break; + default: + return; + } + setcommandmode(); + setconnmode(0); + break; + + case TELOPT_LINEMODE: + if (my_want_state_is_wont(TELOPT_LINEMODE)) + return; + if (SB_EOF()) + return; + switch (SB_GET()) { + case WILL: + lm_will(subpointer, SB_LEN()); + break; + case WONT: + lm_wont(subpointer, SB_LEN()); + break; + case DO: + lm_do(subpointer, SB_LEN()); + break; + case DONT: + lm_dont(subpointer, SB_LEN()); + break; + case LM_SLC: + slc(subpointer, SB_LEN()); + break; + case LM_MODE: + lm_mode(subpointer, SB_LEN(), 0); + break; + default: + break; + } + break; + +#ifdef OLD_ENVIRON + case TELOPT_OLD_ENVIRON: +#endif + case TELOPT_NEW_ENVIRON: + if (SB_EOF()) + return; + switch(SB_PEEK()) { + case TELQUAL_IS: + case TELQUAL_INFO: + if (my_want_state_is_dont(subchar)) + return; + break; + case TELQUAL_SEND: + if (my_want_state_is_wont(subchar)) { + return; + } + break; + default: + return; + } + env_opt(subpointer, SB_LEN()); + break; + + case TELOPT_XDISPLOC: + if (my_want_state_is_wont(TELOPT_XDISPLOC)) + return; + if (SB_EOF()) + return; + if (SB_GET() == TELQUAL_SEND) { + unsigned char temp[50], *dp; + int len; + + if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { + /* + * Something happened, we no longer have a DISPLAY + * variable. So, turn off the option. + */ + send_wont(TELOPT_XDISPLOC, 1); + break; + } + sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, + TELQUAL_IS, dp, IAC, SE); + len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ + + if (len < NETROOM()) { + ring_supply_data(&netoring, temp, len); + printsub('>', temp+2, len - 2); + } +/*@*/ else printf("lm_will: not enough room in buffer\n"); + } + break; + +#if defined(AUTHENTICATION) + case TELOPT_AUTHENTICATION: { + if (!autologin) + break; + if (SB_EOF()) + return; + switch(SB_GET()) { + case TELQUAL_IS: + if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) + return; + auth_is(subpointer, SB_LEN()); + break; + case TELQUAL_SEND: + if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) + return; + auth_send(subpointer, SB_LEN()); + break; + case TELQUAL_REPLY: + if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) + return; + auth_reply(subpointer, SB_LEN()); + break; + case TELQUAL_NAME: + if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) + return; + auth_name(subpointer, SB_LEN()); + break; + } + } + break; +#endif +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: + if (SB_EOF()) + return; + switch(SB_GET()) { + case ENCRYPT_START: + if (my_want_state_is_dont(TELOPT_ENCRYPT)) + return; + encrypt_start(subpointer, SB_LEN()); + break; + case ENCRYPT_END: + if (my_want_state_is_dont(TELOPT_ENCRYPT)) + return; + encrypt_end(); + break; + case ENCRYPT_SUPPORT: + if (my_want_state_is_wont(TELOPT_ENCRYPT)) + return; + encrypt_support(subpointer, SB_LEN()); + break; + case ENCRYPT_REQSTART: + if (my_want_state_is_wont(TELOPT_ENCRYPT)) + return; + encrypt_request_start(subpointer, SB_LEN()); + break; + case ENCRYPT_REQEND: + if (my_want_state_is_wont(TELOPT_ENCRYPT)) + return; + /* + * We can always send an REQEND so that we cannot + * get stuck encrypting. We should only get this + * if we have been able to get in the correct mode + * anyhow. + */ + encrypt_request_end(); + break; + case ENCRYPT_IS: + if (my_want_state_is_dont(TELOPT_ENCRYPT)) + return; + encrypt_is(subpointer, SB_LEN()); + break; + case ENCRYPT_REPLY: + if (my_want_state_is_wont(TELOPT_ENCRYPT)) + return; + encrypt_reply(subpointer, SB_LEN()); + break; + case ENCRYPT_ENC_KEYID: + if (my_want_state_is_dont(TELOPT_ENCRYPT)) + return; + encrypt_enc_keyid(subpointer, SB_LEN()); + break; + case ENCRYPT_DEC_KEYID: + if (my_want_state_is_wont(TELOPT_ENCRYPT)) + return; + encrypt_dec_keyid(subpointer, SB_LEN()); + break; + default: + break; + } + break; +#endif /* ENCRYPTION */ + default: + break; + } +} + +static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; + + void +lm_will(cmd, len) + unsigned char *cmd; + int len; +{ + if (len < 1) { +/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ + return; + } + switch(cmd[0]) { + case LM_FORWARDMASK: /* We shouldn't ever get this... */ + default: + str_lm[3] = DONT; + str_lm[4] = cmd[0]; + if (NETROOM() > sizeof(str_lm)) { + ring_supply_data(&netoring, str_lm, sizeof(str_lm)); + printsub('>', &str_lm[2], sizeof(str_lm)-2); + } +/*@*/ else printf("lm_will: not enough room in buffer\n"); + break; + } +} + + void +lm_wont(cmd, len) + unsigned char *cmd; + int len; +{ + if (len < 1) { +/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ + return; + } + switch(cmd[0]) { + case LM_FORWARDMASK: /* We shouldn't ever get this... */ + default: + /* We are always DONT, so don't respond */ + return; + } +} + + void +lm_do(cmd, len) + unsigned char *cmd; + int len; +{ + if (len < 1) { +/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ + return; + } + switch(cmd[0]) { + case LM_FORWARDMASK: + default: + str_lm[3] = WONT; + str_lm[4] = cmd[0]; + if (NETROOM() > sizeof(str_lm)) { + ring_supply_data(&netoring, str_lm, sizeof(str_lm)); + printsub('>', &str_lm[2], sizeof(str_lm)-2); + } +/*@*/ else printf("lm_do: not enough room in buffer\n"); + break; + } +} + + void +lm_dont(cmd, len) + unsigned char *cmd; + int len; +{ + if (len < 1) { +/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ + return; + } + switch(cmd[0]) { + case LM_FORWARDMASK: + default: + /* we are always WONT, so don't respond */ + break; + } +} + +static unsigned char str_lm_mode[] = { + IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE +}; + + void +lm_mode(cmd, len, init) + unsigned char *cmd; + int len, init; +{ + if (len != 1) + return; + if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) + return; + if (*cmd&MODE_ACK) + return; + linemode = *cmd&(MODE_MASK&~MODE_ACK); + str_lm_mode[4] = linemode; + if (!init) + str_lm_mode[4] |= MODE_ACK; + if (NETROOM() > sizeof(str_lm_mode)) { + ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); + printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); + } +/*@*/ else printf("lm_mode: not enough room in buffer\n"); + setconnmode(0); /* set changed mode */ +} + + + +/* + * slc() + * Handle special character suboption of LINEMODE. + */ + +struct spc { + cc_t val; + cc_t *valp; + char flags; /* Current flags & level */ + char mylevel; /* Maximum level & flags */ +} spc_data[NSLC+1]; + +#define SLC_IMPORT 0 +#define SLC_EXPORT 1 +#define SLC_RVALUE 2 +static int slc_mode = SLC_EXPORT; + + void +slc_init() +{ + register struct spc *spcp; + + localchars = 1; + for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { + spcp->val = 0; + spcp->valp = 0; + spcp->flags = spcp->mylevel = SLC_NOSUPPORT; + } + +#define initfunc(func, flags) { \ + spcp = &spc_data[func]; \ + if (spcp->valp = tcval(func)) { \ + spcp->val = *spcp->valp; \ + spcp->mylevel = SLC_VARIABLE|flags; \ + } else { \ + spcp->val = 0; \ + spcp->mylevel = SLC_DEFAULT; \ + } \ + } + + initfunc(SLC_SYNCH, 0); + /* No BRK */ + initfunc(SLC_AO, 0); + initfunc(SLC_AYT, 0); + /* No EOR */ + initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); + initfunc(SLC_EOF, 0); +#ifndef SYSV_TERMIO + initfunc(SLC_SUSP, SLC_FLUSHIN); +#endif + initfunc(SLC_EC, 0); + initfunc(SLC_EL, 0); +#ifndef SYSV_TERMIO + initfunc(SLC_EW, 0); + initfunc(SLC_RP, 0); + initfunc(SLC_LNEXT, 0); +#endif + initfunc(SLC_XON, 0); + initfunc(SLC_XOFF, 0); +#ifdef SYSV_TERMIO + spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; + spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; +#endif + initfunc(SLC_FORW1, 0); +#ifdef USE_TERMIO + initfunc(SLC_FORW2, 0); + /* No FORW2 */ +#endif + + initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); +#undef initfunc + + if (slc_mode == SLC_EXPORT) + slc_export(); + else + slc_import(1); + +} + + void +slcstate() +{ + printf("Special characters are %s values\n", + slc_mode == SLC_IMPORT ? "remote default" : + slc_mode == SLC_EXPORT ? "local" : + "remote"); +} + + void +slc_mode_export() +{ + slc_mode = SLC_EXPORT; + if (my_state_is_will(TELOPT_LINEMODE)) + slc_export(); +} + + void +slc_mode_import(def) + int def; +{ + slc_mode = def ? SLC_IMPORT : SLC_RVALUE; + if (my_state_is_will(TELOPT_LINEMODE)) + slc_import(def); +} + +unsigned char slc_import_val[] = { + IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE +}; +unsigned char slc_import_def[] = { + IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE +}; + + void +slc_import(def) + int def; +{ + if (NETROOM() > sizeof(slc_import_val)) { + if (def) { + ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); + printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); + } else { + ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); + printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); + } + } +/*@*/ else printf("slc_import: not enough room\n"); +} + + void +slc_export() +{ + register struct spc *spcp; + + TerminalDefaultChars(); + + slc_start_reply(); + for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { + if (spcp->mylevel != SLC_NOSUPPORT) { + if (spcp->val == (cc_t)(_POSIX_VDISABLE)) + spcp->flags = SLC_NOSUPPORT; + else + spcp->flags = spcp->mylevel; + if (spcp->valp) + spcp->val = *spcp->valp; + slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); + } + } + slc_end_reply(); + (void)slc_update(); + setconnmode(1); /* Make sure the character values are set */ +} + + void +slc(cp, len) + register unsigned char *cp; + int len; +{ + register struct spc *spcp; + register int func,level; + + slc_start_reply(); + + for (; len >= 3; len -=3, cp +=3) { + + func = cp[SLC_FUNC]; + + if (func == 0) { + /* + * Client side: always ignore 0 function. + */ + continue; + } + if (func > NSLC) { + if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) + slc_add_reply(func, SLC_NOSUPPORT, 0); + continue; + } + + spcp = &spc_data[func]; + + level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); + + if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && + ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { + continue; + } + + if (level == (SLC_DEFAULT|SLC_ACK)) { + /* + * This is an error condition, the SLC_ACK + * bit should never be set for the SLC_DEFAULT + * level. Our best guess to recover is to + * ignore the SLC_ACK bit. + */ + cp[SLC_FLAGS] &= ~SLC_ACK; + } + + if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { + spcp->val = (cc_t)cp[SLC_VALUE]; + spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ + continue; + } + + level &= ~SLC_ACK; + + if (level <= (spcp->mylevel&SLC_LEVELBITS)) { + spcp->flags = cp[SLC_FLAGS]|SLC_ACK; + spcp->val = (cc_t)cp[SLC_VALUE]; + } + if (level == SLC_DEFAULT) { + if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) + spcp->flags = spcp->mylevel; + else + spcp->flags = SLC_NOSUPPORT; + } + slc_add_reply(func, spcp->flags, spcp->val); + } + slc_end_reply(); + if (slc_update()) + setconnmode(1); /* set the new character values */ +} + + void +slc_check() +{ + register struct spc *spcp; + + slc_start_reply(); + for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { + if (spcp->valp && spcp->val != *spcp->valp) { + spcp->val = *spcp->valp; + if (spcp->val == (cc_t)(_POSIX_VDISABLE)) + spcp->flags = SLC_NOSUPPORT; + else + spcp->flags = spcp->mylevel; + slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); + } + } + slc_end_reply(); + setconnmode(1); +} + + +unsigned char slc_reply[128]; +unsigned char *slc_replyp; + + void +slc_start_reply() +{ + slc_replyp = slc_reply; + *slc_replyp++ = IAC; + *slc_replyp++ = SB; + *slc_replyp++ = TELOPT_LINEMODE; + *slc_replyp++ = LM_SLC; +} + + void +slc_add_reply(func, flags, value) + unsigned char func; + unsigned char flags; + cc_t value; +{ + if ((*slc_replyp++ = func) == IAC) + *slc_replyp++ = IAC; + if ((*slc_replyp++ = flags) == IAC) + *slc_replyp++ = IAC; + if ((*slc_replyp++ = (unsigned char)value) == IAC) + *slc_replyp++ = IAC; +} + + void +slc_end_reply() +{ + register int len; + + *slc_replyp++ = IAC; + *slc_replyp++ = SE; + len = slc_replyp - slc_reply; + if (len <= 6) + return; + if (NETROOM() > len) { + ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); + printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); + } +/*@*/else printf("slc_end_reply: not enough room\n"); +} + + int +slc_update() +{ + register struct spc *spcp; + int need_update = 0; + + for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { + if (!(spcp->flags&SLC_ACK)) + continue; + spcp->flags &= ~SLC_ACK; + if (spcp->valp && (*spcp->valp != spcp->val)) { + *spcp->valp = spcp->val; + need_update = 1; + } + } + return(need_update); +} + +#ifdef OLD_ENVIRON +# ifdef ENV_HACK +/* + * Earlier version of telnet/telnetd from the BSD code had + * the definitions of VALUE and VAR reversed. To ensure + * maximum interoperability, we assume that the server is + * an older BSD server, until proven otherwise. The newer + * BSD servers should be able to handle either definition, + * so it is better to use the wrong values if we don't + * know what type of server it is. + */ +int env_auto = 1; +int old_env_var = OLD_ENV_VAR; +int old_env_value = OLD_ENV_VALUE; +# else +# define old_env_var OLD_ENV_VAR +# define old_env_value OLD_ENV_VALUE +# endif +#endif + + void +env_opt(buf, len) + register unsigned char *buf; + register int len; +{ + register unsigned char *ep = 0, *epc = 0; + register int i; + + switch(buf[0]&0xff) { + case TELQUAL_SEND: + env_opt_start(); + if (len == 1) { + env_opt_add(NULL); + } else for (i = 1; i < len; i++) { + switch (buf[i]&0xff) { +#ifdef OLD_ENVIRON + case OLD_ENV_VAR: +# ifdef ENV_HACK + if (telopt_environ == TELOPT_OLD_ENVIRON + && env_auto) { + /* Server has the same definitions */ + old_env_var = OLD_ENV_VAR; + old_env_value = OLD_ENV_VALUE; + } + /* FALL THROUGH */ +# endif + case OLD_ENV_VALUE: + /* + * Although OLD_ENV_VALUE is not legal, we will + * still recognize it, just in case it is an + * old server that has VAR & VALUE mixed up... + */ + /* FALL THROUGH */ +#else + case NEW_ENV_VAR: +#endif + case ENV_USERVAR: + if (ep) { + *epc = 0; + env_opt_add(ep); + } + ep = epc = &buf[i+1]; + break; + case ENV_ESC: + i++; + /*FALL THROUGH*/ + default: + if (epc) + *epc++ = buf[i]; + break; + } + } + if (ep) { + *epc = 0; + env_opt_add(ep); + } + env_opt_end(1); + break; + + case TELQUAL_IS: + case TELQUAL_INFO: + /* Ignore for now. We shouldn't get it anyway. */ + break; + + default: + break; + } +} + +#define OPT_REPLY_SIZE 256 +unsigned char *opt_reply; +unsigned char *opt_replyp; +unsigned char *opt_replyend; + + void +env_opt_start() +{ + if (opt_reply) + opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); + else + opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); + if (opt_reply == NULL) { +/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); + opt_reply = opt_replyp = opt_replyend = NULL; + return; + } + opt_replyp = opt_reply; + opt_replyend = opt_reply + OPT_REPLY_SIZE; + *opt_replyp++ = IAC; + *opt_replyp++ = SB; + *opt_replyp++ = telopt_environ; + *opt_replyp++ = TELQUAL_IS; +} + + void +env_opt_start_info() +{ + env_opt_start(); + if (opt_replyp) + opt_replyp[-1] = TELQUAL_INFO; +} + + void +env_opt_add(ep) + register unsigned char *ep; +{ + register unsigned char *vp, c; + + if (opt_reply == NULL) /*XXX*/ + return; /*XXX*/ + + if (ep == NULL || *ep == '\0') { + /* Send user defined variables first. */ + env_default(1, 0); + while (ep = env_default(0, 0)) + env_opt_add(ep); + + /* Now add the list of well know variables. */ + env_default(1, 1); + while (ep = env_default(0, 1)) + env_opt_add(ep); + return; + } + vp = env_getvalue(ep); + if (opt_replyp + (vp ? strlen((char *)vp) : 0) + + strlen((char *)ep) + 6 > opt_replyend) + { + register int len; + opt_replyend += OPT_REPLY_SIZE; + len = opt_replyend - opt_reply; + opt_reply = (unsigned char *)realloc(opt_reply, len); + if (opt_reply == NULL) { +/*@*/ printf("env_opt_add: realloc() failed!!!\n"); + opt_reply = opt_replyp = opt_replyend = NULL; + return; + } + opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); + opt_replyend = opt_reply + len; + } + if (opt_welldefined(ep)) +#ifdef OLD_ENVIRON + if (telopt_environ == TELOPT_OLD_ENVIRON) + *opt_replyp++ = old_env_var; + else +#endif + *opt_replyp++ = NEW_ENV_VAR; + else + *opt_replyp++ = ENV_USERVAR; + for (;;) { + while (c = *ep++) { + switch(c&0xff) { + case IAC: + *opt_replyp++ = IAC; + break; + case NEW_ENV_VAR: + case NEW_ENV_VALUE: + case ENV_ESC: + case ENV_USERVAR: + *opt_replyp++ = ENV_ESC; + break; + } + *opt_replyp++ = c; + } + if (ep = vp) { +#ifdef OLD_ENVIRON + if (telopt_environ == TELOPT_OLD_ENVIRON) + *opt_replyp++ = old_env_value; + else +#endif + *opt_replyp++ = NEW_ENV_VALUE; + vp = NULL; + } else + break; + } +} + + int +opt_welldefined(ep) + char *ep; +{ + if ((strcmp(ep, "USER") == 0) || + (strcmp(ep, "DISPLAY") == 0) || + (strcmp(ep, "PRINTER") == 0) || + (strcmp(ep, "SYSTEMTYPE") == 0) || + (strcmp(ep, "JOB") == 0) || + (strcmp(ep, "ACCT") == 0)) + return(1); + return(0); +} + void +env_opt_end(emptyok) + register int emptyok; +{ + register int len; + + len = opt_replyp - opt_reply + 2; + if (emptyok || len > 6) { + *opt_replyp++ = IAC; + *opt_replyp++ = SE; + if (NETROOM() > len) { + ring_supply_data(&netoring, opt_reply, len); + printsub('>', &opt_reply[2], len - 2); + } +/*@*/ else printf("slc_end_reply: not enough room\n"); + } + if (opt_reply) { + free(opt_reply); + opt_reply = opt_replyp = opt_replyend = NULL; + } +} + + + + int +telrcv() +{ + register int c; + register int scc; + register unsigned char *sbp; + int count; + int returnValue = 0; + + scc = 0; + count = 0; + while (TTYROOM() > 2) { + if (scc == 0) { + if (count) { + ring_consumed(&netiring, count); + returnValue = 1; + count = 0; + } + sbp = netiring.consume; + scc = ring_full_consecutive(&netiring); + if (scc == 0) { + /* No more data coming in */ + break; + } + } + + c = *sbp++ & 0xff, scc--; count++; +#ifdef ENCRYPTION + if (decrypt_input) + c = (*decrypt_input)(c); +#endif /* ENCRYPTION */ + + switch (telrcv_state) { + + case TS_CR: + telrcv_state = TS_DATA; + if (c == '\0') { + break; /* Ignore \0 after CR */ + } + else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { + TTYADD(c); + break; + } + /* Else, fall through */ + + case TS_DATA: + if (c == IAC) { + telrcv_state = TS_IAC; + break; + } +# if defined(TN3270) + if (In3270) { + *Ifrontp++ = c; + while (scc > 0) { + c = *sbp++ & 0377, scc--; count++; +#ifdef ENCRYPTION + if (decrypt_input) + c = (*decrypt_input)(c); +#endif /* ENCRYPTION */ + if (c == IAC) { + telrcv_state = TS_IAC; + break; + } + *Ifrontp++ = c; + } + } else +# endif /* defined(TN3270) */ + /* + * The 'crmod' hack (see following) is needed + * since we can't * set CRMOD on output only. + * Machines like MULTICS like to send \r without + * \n; since we must turn off CRMOD to get proper + * input, the mapping is done here (sigh). + */ + if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { + if (scc > 0) { + c = *sbp&0xff; +#ifdef ENCRYPTION + if (decrypt_input) + c = (*decrypt_input)(c); +#endif /* ENCRYPTION */ + if (c == 0) { + sbp++, scc--; count++; + /* a "true" CR */ + TTYADD('\r'); + } else if (my_want_state_is_dont(TELOPT_ECHO) && + (c == '\n')) { + sbp++, scc--; count++; + TTYADD('\n'); + } else { +#ifdef ENCRYPTION + if (decrypt_input) + (*decrypt_input)(-1); +#endif /* ENCRYPTION */ + + TTYADD('\r'); + if (crmod) { + TTYADD('\n'); + } + } + } else { + telrcv_state = TS_CR; + TTYADD('\r'); + if (crmod) { + TTYADD('\n'); + } + } + } else { + TTYADD(c); + } + continue; + + case TS_IAC: +process_iac: + switch (c) { + + case WILL: + telrcv_state = TS_WILL; + continue; + + case WONT: + telrcv_state = TS_WONT; + continue; + + case DO: + telrcv_state = TS_DO; + continue; + + case DONT: + telrcv_state = TS_DONT; + continue; + + case DM: + /* + * We may have missed an urgent notification, + * so make sure we flush whatever is in the + * buffer currently. + */ + printoption("RCVD", IAC, DM); + SYNCHing = 1; + (void) ttyflush(1); + SYNCHing = stilloob(); + settimer(gotDM); + break; + + case SB: + SB_CLEAR(); + telrcv_state = TS_SB; + continue; + +# if defined(TN3270) + case EOR: + if (In3270) { + if (Ibackp == Ifrontp) { + Ibackp = Ifrontp = Ibuf; + ISend = 0; /* should have been! */ + } else { + Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); + ISend = 1; + } + } + printoption("RCVD", IAC, EOR); + break; +# endif /* defined(TN3270) */ + + case IAC: +# if !defined(TN3270) + TTYADD(IAC); +# else /* !defined(TN3270) */ + if (In3270) { + *Ifrontp++ = IAC; + } else { + TTYADD(IAC); + } +# endif /* !defined(TN3270) */ + break; + + case NOP: + case GA: + default: + printoption("RCVD", IAC, c); + break; + } + telrcv_state = TS_DATA; + continue; + + case TS_WILL: + printoption("RCVD", WILL, c); + willoption(c); + SetIn3270(); + telrcv_state = TS_DATA; + continue; + + case TS_WONT: + printoption("RCVD", WONT, c); + wontoption(c); + SetIn3270(); + telrcv_state = TS_DATA; + continue; + + case TS_DO: + printoption("RCVD", DO, c); + dooption(c); + SetIn3270(); + if (c == TELOPT_NAWS) { + sendnaws(); + } else if (c == TELOPT_LFLOW) { + localflow = 1; + setcommandmode(); + setconnmode(0); + } + telrcv_state = TS_DATA; + continue; + + case TS_DONT: + printoption("RCVD", DONT, c); + dontoption(c); + flushline = 1; + setconnmode(0); /* set new tty mode (maybe) */ + SetIn3270(); + telrcv_state = TS_DATA; + continue; + + case TS_SB: + if (c == IAC) { + telrcv_state = TS_SE; + } else { + SB_ACCUM(c); + } + continue; + + case TS_SE: + if (c != SE) { + if (c != IAC) { + /* + * This is an error. We only expect to get + * "IAC IAC" or "IAC SE". Several things may + * have happend. An IAC was not doubled, the + * IAC SE was left off, or another option got + * inserted into the suboption are all possibilities. + * If we assume that the IAC was not doubled, + * and really the IAC SE was left off, we could + * get into an infinate loop here. So, instead, + * we terminate the suboption, and process the + * partial suboption if we can. + */ + SB_ACCUM(IAC); + SB_ACCUM(c); + subpointer -= 2; + SB_TERM(); + + printoption("In SUBOPTION processing, RCVD", IAC, c); + suboption(); /* handle sub-option */ + SetIn3270(); + telrcv_state = TS_IAC; + goto process_iac; + } + SB_ACCUM(c); + telrcv_state = TS_SB; + } else { + SB_ACCUM(IAC); + SB_ACCUM(SE); + subpointer -= 2; + SB_TERM(); + suboption(); /* handle sub-option */ + SetIn3270(); + telrcv_state = TS_DATA; + } + } + } + if (count) + ring_consumed(&netiring, count); + return returnValue||count; +} + +static int bol = 1, local = 0; + + int +rlogin_susp() +{ + if (local) { + local = 0; + bol = 1; + command(0, "z\n", 2); + return(1); + } + return(0); +} + + static int +telsnd() +{ + int tcc; + int count; + int returnValue = 0; + unsigned char *tbp; + + tcc = 0; + count = 0; + while (NETROOM() > 2) { + register int sc; + register int c; + + if (tcc == 0) { + if (count) { + ring_consumed(&ttyiring, count); + returnValue = 1; + count = 0; + } + tbp = ttyiring.consume; + tcc = ring_full_consecutive(&ttyiring); + if (tcc == 0) { + break; + } + } + c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; + if (rlogin != _POSIX_VDISABLE) { + if (bol) { + bol = 0; + if (sc == rlogin) { + local = 1; + continue; + } + } else if (local) { + local = 0; + if (sc == '.' || c == termEofChar) { + bol = 1; + command(0, "close\n", 6); + continue; + } + if (sc == termSuspChar) { + bol = 1; + command(0, "z\n", 2); + continue; + } + if (sc == escape) { + command(0, (char *)tbp, tcc); + bol = 1; + count += tcc; + tcc = 0; + flushline = 1; + break; + } + if (sc != rlogin) { + ++tcc; + --tbp; + --count; + c = sc = rlogin; + } + } + if ((sc == '\n') || (sc == '\r')) + bol = 1; + } else if (sc == escape) { + /* + * Double escape is a pass through of a single escape character. + */ + if (tcc && strip(*tbp) == escape) { + tbp++; + tcc--; + count++; + bol = 0; + } else { + command(0, (char *)tbp, tcc); + bol = 1; + count += tcc; + tcc = 0; + flushline = 1; + break; + } + } else + bol = 0; +#ifdef KLUDGELINEMODE + if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { + if (tcc > 0 && strip(*tbp) == echoc) { + tcc--; tbp++; count++; + } else { + dontlecho = !dontlecho; + settimer(echotoggle); + setconnmode(0); + flushline = 1; + break; + } + } +#endif + if (MODE_LOCAL_CHARS(globalmode)) { + if (TerminalSpecialChars(sc) == 0) { + bol = 1; + break; + } + } + if (my_want_state_is_wont(TELOPT_BINARY)) { + switch (c) { + case '\n': + /* + * If we are in CRMOD mode (\r ==> \n) + * on our local machine, then probably + * a newline (unix) is CRLF (TELNET). + */ + if (MODE_LOCAL_CHARS(globalmode)) { + NETADD('\r'); + } + NETADD('\n'); + bol = flushline = 1; + break; + case '\r': + if (!crlf) { + NET2ADD('\r', '\0'); + } else { + NET2ADD('\r', '\n'); + } + bol = flushline = 1; + break; + case IAC: + NET2ADD(IAC, IAC); + break; + default: + NETADD(c); + break; + } + } else if (c == IAC) { + NET2ADD(IAC, IAC); + } else { + NETADD(c); + } + } + if (count) + ring_consumed(&ttyiring, count); + return returnValue||count; /* Non-zero if we did anything */ +} + +/* + * Scheduler() + * + * Try to do something. + * + * If we do something useful, return 1; else return 0. + * + */ + + + int +Scheduler(block) + int block; /* should we block in the select ? */ +{ + /* One wants to be a bit careful about setting returnValue + * to one, since a one implies we did some useful work, + * and therefore probably won't be called to block next + * time (TN3270 mode only). + */ + int returnValue; + int netin, netout, netex, ttyin, ttyout; + + /* Decide which rings should be processed */ + + netout = ring_full_count(&netoring) && + (flushline || + (my_want_state_is_wont(TELOPT_LINEMODE) +#ifdef KLUDGELINEMODE + && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) +#endif + ) || + my_want_state_is_will(TELOPT_BINARY)); + ttyout = ring_full_count(&ttyoring); + +#if defined(TN3270) + ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); +#else /* defined(TN3270) */ + ttyin = ring_empty_count(&ttyiring); +#endif /* defined(TN3270) */ + +#if defined(TN3270) + netin = ring_empty_count(&netiring); +# else /* !defined(TN3270) */ + netin = !ISend && ring_empty_count(&netiring); +# endif /* !defined(TN3270) */ + + netex = !SYNCHing; + + /* If we have seen a signal recently, reset things */ +# if defined(TN3270) && defined(unix) + if (HaveInput) { + HaveInput = 0; + (void) signal(SIGIO, inputAvailable); + } +#endif /* defined(TN3270) && defined(unix) */ + + /* Call to system code to process rings */ + + returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); + + /* Now, look at the input rings, looking for work to do. */ + + if (ring_full_count(&ttyiring)) { +# if defined(TN3270) + if (In3270) { + int c; + + c = DataFromTerminal(ttyiring.consume, + ring_full_consecutive(&ttyiring)); + if (c) { + returnValue = 1; + ring_consumed(&ttyiring, c); + } + } else { +# endif /* defined(TN3270) */ + returnValue |= telsnd(); +# if defined(TN3270) + } +# endif /* defined(TN3270) */ + } + + if (ring_full_count(&netiring)) { +# if !defined(TN3270) + returnValue |= telrcv(); +# else /* !defined(TN3270) */ + returnValue = Push3270(); +# endif /* !defined(TN3270) */ + } + return returnValue; +} + +/* + * Select from tty and network... + */ + void +telnet(user) + char *user; +{ + sys_telnet_init(); + +#if defined(AUTHENTICATION) || defined(ENCRYPTION) + { + static char local_host[256] = { 0 }; + + if (!local_host[0]) { + gethostname(local_host, sizeof(local_host)); + local_host[sizeof(local_host)-1] = 0; + } + auth_encrypt_init(local_host, hostname, "TELNET", 0); + auth_encrypt_user(user); + } +#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ +# if !defined(TN3270) + if (telnetport) { +#if defined(AUTHENTICATION) + if (autologin) + send_will(TELOPT_AUTHENTICATION, 1); +#endif +#ifdef ENCRYPTION + send_do(TELOPT_ENCRYPT, 1); + send_will(TELOPT_ENCRYPT, 1); +#endif /* ENCRYPTION */ + send_do(TELOPT_SGA, 1); + send_will(TELOPT_TTYPE, 1); + send_will(TELOPT_NAWS, 1); + send_will(TELOPT_TSPEED, 1); + send_will(TELOPT_LFLOW, 1); + send_will(TELOPT_LINEMODE, 1); + send_will(TELOPT_NEW_ENVIRON, 1); + send_do(TELOPT_STATUS, 1); + if (env_getvalue((unsigned char *)"DISPLAY")) + send_will(TELOPT_XDISPLOC, 1); + if (eight) + tel_enter_binary(eight); + } +# endif /* !defined(TN3270) */ + +# if !defined(TN3270) + for (;;) { + int schedValue; + + while ((schedValue = Scheduler(0)) != 0) { + if (schedValue == -1) { + setcommandmode(); + return; + } + } + + if (Scheduler(1) == -1) { + setcommandmode(); + return; + } + } +# else /* !defined(TN3270) */ + for (;;) { + int schedValue; + + while (!In3270 && !shell_active) { + if (Scheduler(1) == -1) { + setcommandmode(); + return; + } + } + + while ((schedValue = Scheduler(0)) != 0) { + if (schedValue == -1) { + setcommandmode(); + return; + } + } + /* If there is data waiting to go out to terminal, don't + * schedule any more data for the terminal. + */ + if (ring_full_count(&ttyoring)) { + schedValue = 1; + } else { + if (shell_active) { + if (shell_continue() == 0) { + ConnectScreen(); + } + } else if (In3270) { + schedValue = DoTerminalOutput(); + } + } + if (schedValue && (shell_active == 0)) { + if (Scheduler(1) == -1) { + setcommandmode(); + return; + } + } + } +# endif /* !defined(TN3270) */ +} + +#if 0 /* XXX - this not being in is a bug */ +/* + * nextitem() + * + * Return the address of the next "item" in the TELNET data + * stream. This will be the address of the next character if + * the current address is a user data character, or it will + * be the address of the character following the TELNET command + * if the current address is a TELNET IAC ("I Am a Command") + * character. + */ + + static char * +nextitem(current) + char *current; +{ + if ((*current&0xff) != IAC) { + return current+1; + } + switch (*(current+1)&0xff) { + case DO: + case DONT: + case WILL: + case WONT: + return current+3; + case SB: /* loop forever looking for the SE */ + { + register char *look = current+2; + + for (;;) { + if ((*look++&0xff) == IAC) { + if ((*look++&0xff) == SE) { + return look; + } + } + } + } + default: + return current+2; + } +} +#endif /* 0 */ + +/* + * netclear() + * + * We are about to do a TELNET SYNCH operation. Clear + * the path to the network. + * + * Things are a bit tricky since we may have sent the first + * byte or so of a previous TELNET command into the network. + * So, we have to scan the network buffer from the beginning + * until we are up to where we want to be. + * + * A side effect of what we do, just to keep things + * simple, is to clear the urgent data pointer. The principal + * caller should be setting the urgent data pointer AFTER calling + * us in any case. + */ + + static void +netclear() +{ +#if 0 /* XXX */ + register char *thisitem, *next; + char *good; +#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ + ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) + + thisitem = netobuf; + + while ((next = nextitem(thisitem)) <= netobuf.send) { + thisitem = next; + } + + /* Now, thisitem is first before/at boundary. */ + + good = netobuf; /* where the good bytes go */ + + while (netoring.add > thisitem) { + if (wewant(thisitem)) { + int length; + + next = thisitem; + do { + next = nextitem(next); + } while (wewant(next) && (nfrontp > next)); + length = next-thisitem; + memcpy(good, thisitem, length); + good += length; + thisitem = next; + } else { + thisitem = nextitem(thisitem); + } + } + +#endif /* 0 */ +} + +/* + * These routines add various telnet commands to the data stream. + */ + + static void +doflush() +{ + NET2ADD(IAC, DO); + NETADD(TELOPT_TM); + flushline = 1; + flushout = 1; + (void) ttyflush(1); /* Flush/drop output */ + /* do printoption AFTER flush, otherwise the output gets tossed... */ + printoption("SENT", DO, TELOPT_TM); +} + + void +xmitAO() +{ + NET2ADD(IAC, AO); + printoption("SENT", IAC, AO); + if (autoflush) { + doflush(); + } +} + + + void +xmitEL() +{ + NET2ADD(IAC, EL); + printoption("SENT", IAC, EL); +} + + void +xmitEC() +{ + NET2ADD(IAC, EC); + printoption("SENT", IAC, EC); +} + + + int +dosynch() +{ + netclear(); /* clear the path to the network */ + NETADD(IAC); + setneturg(); + NETADD(DM); + printoption("SENT", IAC, DM); + return 1; +} + +int want_status_response = 0; + + int +get_status() +{ + unsigned char tmp[16]; + register unsigned char *cp; + + if (my_want_state_is_dont(TELOPT_STATUS)) { + printf("Remote side does not support STATUS option\n"); + return 0; + } + cp = tmp; + + *cp++ = IAC; + *cp++ = SB; + *cp++ = TELOPT_STATUS; + *cp++ = TELQUAL_SEND; + *cp++ = IAC; + *cp++ = SE; + if (NETROOM() >= cp - tmp) { + ring_supply_data(&netoring, tmp, cp-tmp); + printsub('>', tmp+2, cp - tmp - 2); + } + ++want_status_response; + return 1; +} + + void +intp() +{ + NET2ADD(IAC, IP); + printoption("SENT", IAC, IP); + flushline = 1; + if (autoflush) { + doflush(); + } + if (autosynch) { + dosynch(); + } +} + + void +sendbrk() +{ + NET2ADD(IAC, BREAK); + printoption("SENT", IAC, BREAK); + flushline = 1; + if (autoflush) { + doflush(); + } + if (autosynch) { + dosynch(); + } +} + + void +sendabort() +{ + NET2ADD(IAC, ABORT); + printoption("SENT", IAC, ABORT); + flushline = 1; + if (autoflush) { + doflush(); + } + if (autosynch) { + dosynch(); + } +} + + void +sendsusp() +{ + NET2ADD(IAC, SUSP); + printoption("SENT", IAC, SUSP); + flushline = 1; + if (autoflush) { + doflush(); + } + if (autosynch) { + dosynch(); + } +} + + void +sendeof() +{ + NET2ADD(IAC, xEOF); + printoption("SENT", IAC, xEOF); +} + + void +sendayt() +{ + NET2ADD(IAC, AYT); + printoption("SENT", IAC, AYT); +} + +/* + * Send a window size update to the remote system. + */ + + void +sendnaws() +{ + long rows, cols; + unsigned char tmp[16]; + register unsigned char *cp; + + if (my_state_is_wont(TELOPT_NAWS)) + return; + +#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ + if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } + + if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ + return; + } + + cp = tmp; + + *cp++ = IAC; + *cp++ = SB; + *cp++ = TELOPT_NAWS; + PUTSHORT(cp, cols); + PUTSHORT(cp, rows); + *cp++ = IAC; + *cp++ = SE; + if (NETROOM() >= cp - tmp) { + ring_supply_data(&netoring, tmp, cp-tmp); + printsub('>', tmp+2, cp - tmp - 2); + } +} + + void +tel_enter_binary(rw) + int rw; +{ + if (rw&1) + send_do(TELOPT_BINARY, 1); + if (rw&2) + send_will(TELOPT_BINARY, 1); +} + + void +tel_leave_binary(rw) + int rw; +{ + if (rw&1) + send_dont(TELOPT_BINARY, 1); + if (rw&2) + send_wont(TELOPT_BINARY, 1); +} diff --git a/usr.bin/telnet/terminal.c b/usr.bin/telnet/terminal.c new file mode 100644 index 0000000..b6d3b86 --- /dev/null +++ b/usr.bin/telnet/terminal.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)terminal.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include "ring.h" + +#include "externs.h" +#include "types.h" + +Ring ttyoring, ttyiring; +unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ]; + +int termdata; /* Debugging flag */ + +#ifdef USE_TERMIO +# ifndef VDISCARD +cc_t termFlushChar; +# endif +# ifndef VLNEXT +cc_t termLiteralNextChar; +# endif +# ifndef VSUSP +cc_t termSuspChar; +# endif +# ifndef VWERASE +cc_t termWerasChar; +# endif +# ifndef VREPRINT +cc_t termRprntChar; +# endif +# ifndef VSTART +cc_t termStartChar; +# endif +# ifndef VSTOP +cc_t termStopChar; +# endif +# ifndef VEOL +cc_t termForw1Char; +# endif +# ifndef VEOL2 +cc_t termForw2Char; +# endif +# ifndef VSTATUS +cc_t termAytChar; +# endif +#else +cc_t termForw2Char; +cc_t termAytChar; +#endif + +/* + * initialize the terminal data structures. + */ + + void +init_terminal() +{ + if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) { + exit(1); + } + if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) { + exit(1); + } + autoflush = TerminalAutoFlush(); +} + + +/* + * Send as much data as possible to the terminal. + * + * Return value: + * -1: No useful work done, data waiting to go out. + * 0: No data was waiting, so nothing was done. + * 1: All waiting data was written out. + * n: All data - n was written out. + */ + + + int +ttyflush(drop) + int drop; +{ + register int n, n0, n1; + + n0 = ring_full_count(&ttyoring); + if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) { + if (drop) { + TerminalFlushOutput(); + /* we leave 'n' alone! */ + } else { + n = TerminalWrite(ttyoring.consume, n); + } + } + if (n > 0) { + if (termdata && n) { + Dump('>', ttyoring.consume, n); + } + /* + * If we wrote everything, and the full count is + * larger than what we wrote, then write the + * rest of the buffer. + */ + if (n1 == n && n0 > n) { + n1 = n0 - n; + if (!drop) + n1 = TerminalWrite(ttyoring.bottom, n1); + n += n1; + } + ring_consumed(&ttyoring, n); + } + if (n < 0) + return -1; + if (n == n0) { + if (n0) + return -1; + return 0; + } + return n0 - n + 1; +} + + +/* + * These routines decides on what the mode should be (based on the values + * of various global variables). + */ + + + int +getconnmode() +{ + extern int linemode; + int mode = 0; +#ifdef KLUDGELINEMODE + extern int kludgelinemode; +#endif + + if (In3270) + return(MODE_FLOW); + + if (my_want_state_is_dont(TELOPT_ECHO)) + mode |= MODE_ECHO; + + if (localflow) + mode |= MODE_FLOW; + + if (my_want_state_is_will(TELOPT_BINARY)) + mode |= MODE_INBIN; + + if (his_want_state_is_will(TELOPT_BINARY)) + mode |= MODE_OUTBIN; + +#ifdef KLUDGELINEMODE + if (kludgelinemode) { + if (my_want_state_is_dont(TELOPT_SGA)) { + mode |= (MODE_TRAPSIG|MODE_EDIT); + if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { + mode &= ~MODE_ECHO; + } + } + return(mode); + } +#endif + if (my_want_state_is_will(TELOPT_LINEMODE)) + mode |= linemode; + return(mode); +} + + void +setconnmode(force) + int force; +{ +#ifdef ENCRYPTION + static int enc_passwd = 0; +#endif /* ENCRYPTION */ + register int newmode; + + newmode = getconnmode()|(force?MODE_FORCE:0); + + TerminalNewMode(newmode); + +#ifdef ENCRYPTION + if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) { + if (my_want_state_is_will(TELOPT_ENCRYPT) + && (enc_passwd == 0) && !encrypt_output) { + encrypt_request_start(0, 0); + enc_passwd = 1; + } + } else { + if (enc_passwd) { + encrypt_request_end(); + enc_passwd = 0; + } + } +#endif /* ENCRYPTION */ + +} + + + void +setcommandmode() +{ + TerminalNewMode(-1); +} diff --git a/usr.bin/telnet/tn3270.c b/usr.bin/telnet/tn3270.c new file mode 100644 index 0000000..1f285cf --- /dev/null +++ b/usr.bin/telnet/tn3270.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)tn3270.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include "general.h" + +#include "defines.h" +#include "ring.h" +#include "externs.h" +#include "fdset.h" + +#if defined(TN3270) + +#include "../ctlr/screen.h" +#include "../general/globals.h" + +#include "../sys_curses/telextrn.h" +#include "../ctlr/externs.h" + +#if defined(unix) +int + HaveInput, /* There is input available to scan */ + cursesdata, /* Do we dump curses data? */ + sigiocount; /* Number of times we got a SIGIO */ + +char tline[200]; +char *transcom = 0; /* transparent mode command (default: none) */ +#endif /* defined(unix) */ + +char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; + +static char sb_terminal[] = { IAC, SB, + TELOPT_TTYPE, TELQUAL_IS, + 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', + IAC, SE }; +#define SBTERMMODEL 13 + +static int + Sent3270TerminalType; /* Have we said we are a 3270? */ + +#endif /* defined(TN3270) */ + + + void +init_3270() +{ +#if defined(TN3270) +#if defined(unix) + HaveInput = 0; + sigiocount = 0; +#endif /* defined(unix) */ + Sent3270TerminalType = 0; + Ifrontp = Ibackp = Ibuf; + init_ctlr(); /* Initialize some things */ + init_keyboard(); + init_screen(); + init_system(); +#endif /* defined(TN3270) */ +} + + +#if defined(TN3270) + +/* + * DataToNetwork - queue up some data to go to network. If "done" is set, + * then when last byte is queued, we add on an IAC EOR sequence (so, + * don't call us with "done" until you want that done...) + * + * We actually do send all the data to the network buffer, since our + * only client needs for us to do that. + */ + + int +DataToNetwork(buffer, count, done) + register char *buffer; /* where the data is */ + register int count; /* how much to send */ + int done; /* is this the last of a logical block */ +{ + register int loop, c; + int origCount; + + origCount = count; + + while (count) { + /* If not enough room for EORs, IACs, etc., wait */ + if (NETROOM() < 6) { + fd_set o; + + FD_ZERO(&o); + netflush(); + while (NETROOM() < 6) { + FD_SET(net, &o); + (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, + (struct timeval *) 0); + netflush(); + } + } + c = ring_empty_count(&netoring); + if (c > count) { + c = count; + } + loop = c; + while (loop) { + if (((unsigned char)*buffer) == IAC) { + break; + } + buffer++; + loop--; + } + if ((c = c-loop)) { + ring_supply_data(&netoring, buffer-c, c); + count -= c; + } + if (loop) { + NET2ADD(IAC, IAC); + count--; + buffer++; + } + } + + if (done) { + NET2ADD(IAC, EOR); + netflush(); /* try to move along as quickly as ... */ + } + return(origCount - count); +} + + +#if defined(unix) + void +inputAvailable(signo) + int signo; +{ + HaveInput = 1; + sigiocount++; +} +#endif /* defined(unix) */ + + void +outputPurge() +{ + (void) ttyflush(1); +} + + +/* + * The following routines are places where the various tn3270 + * routines make calls into telnet.c. + */ + +/* + * DataToTerminal - queue up some data to go to terminal. + * + * Note: there are people who call us and depend on our processing + * *all* the data at one time (thus the select). + */ + + int +DataToTerminal(buffer, count) + register char *buffer; /* where the data is */ + register int count; /* how much to send */ +{ + register int c; + int origCount; + + origCount = count; + + while (count) { + if (TTYROOM() == 0) { +#if defined(unix) + fd_set o; + + FD_ZERO(&o); +#endif /* defined(unix) */ + (void) ttyflush(0); + while (TTYROOM() == 0) { +#if defined(unix) + FD_SET(tout, &o); + (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, + (struct timeval *) 0); +#endif /* defined(unix) */ + (void) ttyflush(0); + } + } + c = TTYROOM(); + if (c > count) { + c = count; + } + ring_supply_data(&ttyoring, buffer, c); + count -= c; + buffer += c; + } + return(origCount); +} + + +/* + * Push3270 - Try to send data along the 3270 output (to screen) direction. + */ + + int +Push3270() +{ + int save = ring_full_count(&netiring); + + if (save) { + if (Ifrontp+save > Ibuf+sizeof Ibuf) { + if (Ibackp != Ibuf) { + memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); + Ifrontp -= (Ibackp-Ibuf); + Ibackp = Ibuf; + } + } + if (Ifrontp+save < Ibuf+sizeof Ibuf) { + (void)telrcv(); + } + } + return save != ring_full_count(&netiring); +} + + +/* + * Finish3270 - get the last dregs of 3270 data out to the terminal + * before quitting. + */ + + void +Finish3270() +{ + while (Push3270() || !DoTerminalOutput()) { +#if defined(unix) + HaveInput = 0; +#endif /* defined(unix) */ + ; + } +} + + +/* StringToTerminal - output a null terminated string to the terminal */ + + void +StringToTerminal(s) + char *s; +{ + int count; + + count = strlen(s); + if (count) { + (void) DataToTerminal(s, count); /* we know it always goes... */ + } +} + + +#if ((!defined(NOT43)) || defined(PUTCHAR)) +/* _putchar - output a single character to the terminal. This name is so that + * curses(3x) can call us to send out data. + */ + + void +_putchar(c) + char c; +{ +#if defined(sun) /* SunOS 4.0 bug */ + c &= 0x7f; +#endif /* defined(sun) */ + if (cursesdata) { + Dump('>', &c, 1); + } + if (!TTYROOM()) { + (void) DataToTerminal(&c, 1); + } else { + TTYADD(c); + } +} +#endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ + + void +SetIn3270() +{ + if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY) + && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) { + if (!In3270) { + In3270 = 1; + Init3270(); /* Initialize 3270 functions */ + /* initialize terminal key mapping */ + InitTerminal(); /* Start terminal going */ + setconnmode(0); + } + } else { + if (In3270) { + StopScreen(1); + In3270 = 0; + Stop3270(); /* Tell 3270 we aren't here anymore */ + setconnmode(0); + } + } +} + +/* + * tn3270_ttype() + * + * Send a response to a terminal type negotiation. + * + * Return '0' if no more responses to send; '1' if a response sent. + */ + + int +tn3270_ttype() +{ + /* + * Try to send a 3270 type terminal name. Decide which one based + * on the format of our screen, and (in the future) color + * capaiblities. + */ + InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ + if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { + Sent3270TerminalType = 1; + if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { + MaxNumberLines = 27; + MaxNumberColumns = 132; + sb_terminal[SBTERMMODEL] = '5'; + } else if (MaxNumberLines >= 43) { + MaxNumberLines = 43; + MaxNumberColumns = 80; + sb_terminal[SBTERMMODEL] = '4'; + } else if (MaxNumberLines >= 32) { + MaxNumberLines = 32; + MaxNumberColumns = 80; + sb_terminal[SBTERMMODEL] = '3'; + } else { + MaxNumberLines = 24; + MaxNumberColumns = 80; + sb_terminal[SBTERMMODEL] = '2'; + } + NumberLines = 24; /* before we start out... */ + NumberColumns = 80; + ScreenSize = NumberLines*NumberColumns; + if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { + ExitString("Programming error: MAXSCREENSIZE too small.\n", + 1); + /*NOTREACHED*/ + } + printsub('>', sb_terminal+2, sizeof sb_terminal-2); + ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); + return 1; + } else { + return 0; + } +} + +#if defined(unix) + int +settranscom(argc, argv) + int argc; + char *argv[]; +{ + int i; + + if (argc == 1 && transcom) { + transcom = 0; + } + if (argc == 1) { + return 1; + } + transcom = tline; + (void) strcpy(transcom, argv[1]); + for (i = 2; i < argc; ++i) { + (void) strcat(transcom, " "); + (void) strcat(transcom, argv[i]); + } + return 1; +} +#endif /* defined(unix) */ + +#endif /* defined(TN3270) */ diff --git a/usr.bin/telnet/types.h b/usr.bin/telnet/types.h new file mode 100644 index 0000000..191d311 --- /dev/null +++ b/usr.bin/telnet/types.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1988, 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. + * + * @(#)types.h 8.1 (Berkeley) 6/6/93 + */ + +typedef struct { + char *modedescriptions; + char modetype; +} Modelist; + +extern Modelist modelist[]; + +typedef struct { + int + system, /* what the current time is */ + echotoggle, /* last time user entered echo character */ + modenegotiated, /* last time operating mode negotiated */ + didnetreceive, /* last time we read data from network */ + gotDM; /* when did we last see a data mark */ +} Clocks; + +extern Clocks clocks; diff --git a/usr.bin/telnet/utilities.c b/usr.bin/telnet/utilities.c new file mode 100644 index 0000000..70cf567 --- /dev/null +++ b/usr.bin/telnet/utilities.c @@ -0,0 +1,939 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)utilities.c 8.2 (Berkeley) 12/15/93"; +#endif /* not lint */ + +#define TELOPTS +#define TELCMDS +#define SLC_NAMES +#include +#include +#include + +#include + +#include "general.h" + +#include "fdset.h" + +#include "ring.h" + +#include "defines.h" + +#include "externs.h" + +FILE *NetTrace = 0; /* Not in bss, since needs to stay */ +int prettydump; + +/* + * upcase() + * + * Upcase (in place) the argument. + */ + + void +upcase(argument) + register char *argument; +{ + register int c; + + while ((c = *argument) != 0) { + if (islower(c)) { + *argument = toupper(c); + } + argument++; + } +} + +/* + * SetSockOpt() + * + * Compensate for differences in 4.2 and 4.3 systems. + */ + + int +SetSockOpt(fd, level, option, yesno) + int fd, level, option, yesno; +{ +#ifndef NOT43 + return setsockopt(fd, level, option, + (char *)&yesno, sizeof yesno); +#else /* NOT43 */ + if (yesno == 0) { /* Can't do that in 4.2! */ + fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", + option); + return -1; + } + return setsockopt(fd, level, option, 0, 0); +#endif /* NOT43 */ +} + +/* + * The following are routines used to print out debugging information. + */ + +unsigned char NetTraceFile[256] = "(standard output)"; + + void +SetNetTrace(file) + register char *file; +{ + if (NetTrace && NetTrace != stdout) + fclose(NetTrace); + if (file && (strcmp(file, "-") != 0)) { + NetTrace = fopen(file, "w"); + if (NetTrace) { + strcpy((char *)NetTraceFile, file); + return; + } + fprintf(stderr, "Cannot open %s.\n", file); + } + NetTrace = stdout; + strcpy((char *)NetTraceFile, "(standard output)"); +} + + void +Dump(direction, buffer, length) + char direction; + unsigned char *buffer; + int length; +{ +# define BYTES_PER_LINE 32 +# define min(x,y) ((x' */ + unsigned char *pointer; /* where suboption data sits */ + int length; /* length of suboption data */ +{ + register int i; + char buf[512]; + extern int want_status_response; + + if (showoptions || direction == 0 || + (want_status_response && (pointer[0] == TELOPT_STATUS))) { + if (direction) { + fprintf(NetTrace, "%s IAC SB ", + (direction == '<')? "RCVD":"SENT"); + if (length >= 3) { + register int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if (i != IAC || j != SE) { + fprintf(NetTrace, "(terminated by "); + if (TELOPT_OK(i)) + fprintf(NetTrace, "%s ", TELOPT(i)); + else if (TELCMD_OK(i)) + fprintf(NetTrace, "%s ", TELCMD(i)); + else + fprintf(NetTrace, "%d ", i); + if (TELOPT_OK(j)) + fprintf(NetTrace, "%s", TELOPT(j)); + else if (TELCMD_OK(j)) + fprintf(NetTrace, "%s", TELCMD(j)); + else + fprintf(NetTrace, "%d", j); + fprintf(NetTrace, ", not IAC SE!) "); + } + } + length -= 2; + } + if (length < 1) { + fprintf(NetTrace, "(Empty suboption??\?)"); + if (NetTrace == stdout) + fflush(NetTrace); + return; + } + switch (pointer[0]) { + case TELOPT_TTYPE: + fprintf(NetTrace, "TERMINAL-TYPE "); + switch (pointer[1]) { + case TELQUAL_IS: + fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); + break; + case TELQUAL_SEND: + fprintf(NetTrace, "SEND"); + break; + default: + fprintf(NetTrace, + "- unknown qualifier %d (0x%x).", + pointer[1], pointer[1]); + } + break; + case TELOPT_TSPEED: + fprintf(NetTrace, "TERMINAL-SPEED"); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case TELQUAL_IS: + fprintf(NetTrace, " IS "); + fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); + break; + default: + if (pointer[1] == 1) + fprintf(NetTrace, " SEND"); + else + fprintf(NetTrace, " %d (unknown)", pointer[1]); + for (i = 2; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + } + break; + + case TELOPT_LFLOW: + fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case LFLOW_OFF: + fprintf(NetTrace, " OFF"); break; + case LFLOW_ON: + fprintf(NetTrace, " ON"); break; + case LFLOW_RESTART_ANY: + fprintf(NetTrace, " RESTART-ANY"); break; + case LFLOW_RESTART_XON: + fprintf(NetTrace, " RESTART-XON"); break; + default: + fprintf(NetTrace, " %d (unknown)", pointer[1]); + } + for (i = 2; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + + case TELOPT_NAWS: + fprintf(NetTrace, "NAWS"); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + if (length == 2) { + fprintf(NetTrace, " ?%d?", pointer[1]); + break; + } + fprintf(NetTrace, " %d %d (%d)", + pointer[1], pointer[2], + (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); + if (length == 4) { + fprintf(NetTrace, " ?%d?", pointer[3]); + break; + } + fprintf(NetTrace, " %d %d (%d)", + pointer[3], pointer[4], + (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); + for (i = 5; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + +#if defined(AUTHENTICATION) + case TELOPT_AUTHENTICATION: + fprintf(NetTrace, "AUTHENTICATION"); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case TELQUAL_REPLY: + case TELQUAL_IS: + fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? + "IS" : "REPLY"); + if (AUTHTYPE_NAME_OK(pointer[2])) + fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); + else + fprintf(NetTrace, "%d ", pointer[2]); + if (length < 3) { + fprintf(NetTrace, "(partial suboption??\?)"); + break; + } + fprintf(NetTrace, "%s|%s", + ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? + "CLIENT" : "SERVER", + ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? + "MUTUAL" : "ONE-WAY"); + + auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); + fprintf(NetTrace, "%s", buf); + break; + + case TELQUAL_SEND: + i = 2; + fprintf(NetTrace, " SEND "); + while (i < length) { + if (AUTHTYPE_NAME_OK(pointer[i])) + fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); + else + fprintf(NetTrace, "%d ", pointer[i]); + if (++i >= length) { + fprintf(NetTrace, "(partial suboption??\?)"); + break; + } + fprintf(NetTrace, "%s|%s ", + ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? + "CLIENT" : "SERVER", + ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? + "MUTUAL" : "ONE-WAY"); + ++i; + } + break; + + case TELQUAL_NAME: + i = 2; + fprintf(NetTrace, " NAME \""); + while (i < length) + putc(pointer[i++], NetTrace); + putc('"', NetTrace); + break; + + default: + for (i = 2; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + } + break; +#endif + +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: + fprintf(NetTrace, "ENCRYPT"); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case ENCRYPT_START: + fprintf(NetTrace, " START"); + break; + + case ENCRYPT_END: + fprintf(NetTrace, " END"); + break; + + case ENCRYPT_REQSTART: + fprintf(NetTrace, " REQUEST-START"); + break; + + case ENCRYPT_REQEND: + fprintf(NetTrace, " REQUEST-END"); + break; + + case ENCRYPT_IS: + case ENCRYPT_REPLY: + fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? + "IS" : "REPLY"); + if (length < 3) { + fprintf(NetTrace, " (partial suboption??\?)"); + break; + } + if (ENCTYPE_NAME_OK(pointer[2])) + fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); + else + fprintf(NetTrace, " %d (unknown)", pointer[2]); + + encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); + fprintf(NetTrace, "%s", buf); + break; + + case ENCRYPT_SUPPORT: + i = 2; + fprintf(NetTrace, " SUPPORT "); + while (i < length) { + if (ENCTYPE_NAME_OK(pointer[i])) + fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); + else + fprintf(NetTrace, "%d ", pointer[i]); + i++; + } + break; + + case ENCRYPT_ENC_KEYID: + fprintf(NetTrace, " ENC_KEYID "); + goto encommon; + + case ENCRYPT_DEC_KEYID: + fprintf(NetTrace, " DEC_KEYID "); + goto encommon; + + default: + fprintf(NetTrace, " %d (unknown)", pointer[1]); + encommon: + for (i = 2; i < length; i++) + fprintf(NetTrace, " %d", pointer[i]); + break; + } + break; +#endif /* ENCRYPTION */ + + case TELOPT_LINEMODE: + fprintf(NetTrace, "LINEMODE "); + if (length < 2) { + fprintf(NetTrace, " (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case WILL: + fprintf(NetTrace, "WILL "); + goto common; + case WONT: + fprintf(NetTrace, "WONT "); + goto common; + case DO: + fprintf(NetTrace, "DO "); + goto common; + case DONT: + fprintf(NetTrace, "DONT "); + common: + if (length < 3) { + fprintf(NetTrace, "(no option??\?)"); + break; + } + switch (pointer[2]) { + case LM_FORWARDMASK: + fprintf(NetTrace, "Forward Mask"); + for (i = 3; i < length; i++) + fprintf(NetTrace, " %x", pointer[i]); + break; + default: + fprintf(NetTrace, "%d (unknown)", pointer[2]); + for (i = 3; i < length; i++) + fprintf(NetTrace, " %d", pointer[i]); + break; + } + break; + + case LM_SLC: + fprintf(NetTrace, "SLC"); + for (i = 2; i < length - 2; i += 3) { + if (SLC_NAME_OK(pointer[i+SLC_FUNC])) + fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); + else + fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); + switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { + case SLC_NOSUPPORT: + fprintf(NetTrace, " NOSUPPORT"); break; + case SLC_CANTCHANGE: + fprintf(NetTrace, " CANTCHANGE"); break; + case SLC_VARIABLE: + fprintf(NetTrace, " VARIABLE"); break; + case SLC_DEFAULT: + fprintf(NetTrace, " DEFAULT"); break; + } + fprintf(NetTrace, "%s%s%s", + pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", + pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", + pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); + if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| + SLC_FLUSHOUT| SLC_LEVELBITS)) + fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); + fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); + if ((pointer[i+SLC_VALUE] == IAC) && + (pointer[i+SLC_VALUE+1] == IAC)) + i++; + } + for (; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + + case LM_MODE: + fprintf(NetTrace, "MODE "); + if (length < 3) { + fprintf(NetTrace, "(no mode??\?)"); + break; + } + { + char tbuf[64]; + sprintf(tbuf, "%s%s%s%s%s", + pointer[2]&MODE_EDIT ? "|EDIT" : "", + pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", + pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", + pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", + pointer[2]&MODE_ACK ? "|ACK" : ""); + fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); + } + if (pointer[2]&~(MODE_MASK)) + fprintf(NetTrace, " (0x%x)", pointer[2]); + for (i = 3; i < length; i++) + fprintf(NetTrace, " ?0x%x?", pointer[i]); + break; + default: + fprintf(NetTrace, "%d (unknown)", pointer[1]); + for (i = 2; i < length; i++) + fprintf(NetTrace, " %d", pointer[i]); + } + break; + + case TELOPT_STATUS: { + register char *cp; + register int j, k; + + fprintf(NetTrace, "STATUS"); + + switch (pointer[1]) { + default: + if (pointer[1] == TELQUAL_SEND) + fprintf(NetTrace, " SEND"); + else + fprintf(NetTrace, " %d (unknown)", pointer[1]); + for (i = 2; i < length; i++) + fprintf(NetTrace, " ?%d?", pointer[i]); + break; + case TELQUAL_IS: + if (--want_status_response < 0) + want_status_response = 0; + if (NetTrace == stdout) + fprintf(NetTrace, " IS\r\n"); + else + fprintf(NetTrace, " IS\n"); + + for (i = 2; i < length; i++) { + switch(pointer[i]) { + case DO: cp = "DO"; goto common2; + case DONT: cp = "DONT"; goto common2; + case WILL: cp = "WILL"; goto common2; + case WONT: cp = "WONT"; goto common2; + common2: + i++; + if (TELOPT_OK((int)pointer[i])) + fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); + else + fprintf(NetTrace, " %s %d", cp, pointer[i]); + + if (NetTrace == stdout) + fprintf(NetTrace, "\r\n"); + else + fprintf(NetTrace, "\n"); + break; + + case SB: + fprintf(NetTrace, " SB "); + i++; + j = k = i; + while (j < length) { + if (pointer[j] == SE) { + if (j+1 == length) + break; + if (pointer[j+1] == SE) + j++; + else + break; + } + pointer[k++] = pointer[j++]; + } + printsub(0, &pointer[i], k - i); + if (i < length) { + fprintf(NetTrace, " SE"); + i = j; + } else + i = j - 1; + + if (NetTrace == stdout) + fprintf(NetTrace, "\r\n"); + else + fprintf(NetTrace, "\n"); + + break; + + default: + fprintf(NetTrace, " %d", pointer[i]); + break; + } + } + break; + } + break; + } + + case TELOPT_XDISPLOC: + fprintf(NetTrace, "X-DISPLAY-LOCATION "); + switch (pointer[1]) { + case TELQUAL_IS: + fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); + break; + case TELQUAL_SEND: + fprintf(NetTrace, "SEND"); + break; + default: + fprintf(NetTrace, "- unknown qualifier %d (0x%x).", + pointer[1], pointer[1]); + } + break; + + case TELOPT_NEW_ENVIRON: + fprintf(NetTrace, "NEW-ENVIRON "); +#ifdef OLD_ENVIRON + goto env_common1; + case TELOPT_OLD_ENVIRON: + fprintf(NetTrace, "OLD-ENVIRON"); + env_common1: +#endif + switch (pointer[1]) { + case TELQUAL_IS: + fprintf(NetTrace, "IS "); + goto env_common; + case TELQUAL_SEND: + fprintf(NetTrace, "SEND "); + goto env_common; + case TELQUAL_INFO: + fprintf(NetTrace, "INFO "); + env_common: + { + register int noquote = 2; +#if defined(ENV_HACK) && defined(OLD_ENVIRON) + extern int old_env_var, old_env_value; +#endif + for (i = 2; i < length; i++ ) { + switch (pointer[i]) { + case NEW_ENV_VALUE: +#ifdef OLD_ENVIRON + /* case NEW_ENV_OVAR: */ + if (pointer[0] == TELOPT_OLD_ENVIRON) { +# ifdef ENV_HACK + if (old_env_var == OLD_ENV_VALUE) + fprintf(NetTrace, "\" (VALUE) " + noquote); + else +# endif + fprintf(NetTrace, "\" VAR " + noquote); + } else +#endif /* OLD_ENVIRON */ + fprintf(NetTrace, "\" VALUE " + noquote); + noquote = 2; + break; + + case NEW_ENV_VAR: +#ifdef OLD_ENVIRON + /* case OLD_ENV_VALUE: */ + if (pointer[0] == TELOPT_OLD_ENVIRON) { +# ifdef ENV_HACK + if (old_env_value == OLD_ENV_VAR) + fprintf(NetTrace, "\" (VAR) " + noquote); + else +# endif + fprintf(NetTrace, "\" VALUE " + noquote); + } else +#endif /* OLD_ENVIRON */ + fprintf(NetTrace, "\" VAR " + noquote); + noquote = 2; + break; + + case ENV_ESC: + fprintf(NetTrace, "\" ESC " + noquote); + noquote = 2; + break; + + case ENV_USERVAR: + fprintf(NetTrace, "\" USERVAR " + noquote); + noquote = 2; + break; + + default: + def_case: + if (isprint(pointer[i]) && pointer[i] != '"') { + if (noquote) { + putc('"', NetTrace); + noquote = 0; + } + putc(pointer[i], NetTrace); + } else { + fprintf(NetTrace, "\" %03o " + noquote, + pointer[i]); + noquote = 2; + } + break; + } + } + if (!noquote) + putc('"', NetTrace); + break; + } + } + break; + + default: + if (TELOPT_OK(pointer[0])) + fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); + else + fprintf(NetTrace, "%d (unknown)", pointer[0]); + for (i = 1; i < length; i++) + fprintf(NetTrace, " %d", pointer[i]); + break; + } + if (direction) { + if (NetTrace == stdout) + fprintf(NetTrace, "\r\n"); + else + fprintf(NetTrace, "\n"); + } + if (NetTrace == stdout) + fflush(NetTrace); + } +} + +/* EmptyTerminal - called to make sure that the terminal buffer is empty. + * Note that we consider the buffer to run all the + * way to the kernel (thus the select). + */ + + void +EmptyTerminal() +{ +#if defined(unix) + fd_set o; + + FD_ZERO(&o); +#endif /* defined(unix) */ + + if (TTYBYTES() == 0) { +#if defined(unix) + FD_SET(tout, &o); + (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, + (struct timeval *) 0); /* wait for TTLOWAT */ +#endif /* defined(unix) */ + } else { + while (TTYBYTES()) { + (void) ttyflush(0); +#if defined(unix) + FD_SET(tout, &o); + (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, + (struct timeval *) 0); /* wait for TTLOWAT */ +#endif /* defined(unix) */ + } + } +} + + void +SetForExit() +{ + setconnmode(0); +#if defined(TN3270) + if (In3270) { + Finish3270(); + } +#else /* defined(TN3270) */ + do { + (void)telrcv(); /* Process any incoming data */ + EmptyTerminal(); + } while (ring_full_count(&netiring)); /* While there is any */ +#endif /* defined(TN3270) */ + setcommandmode(); + fflush(stdout); + fflush(stderr); +#if defined(TN3270) + if (In3270) { + StopScreen(1); + } +#endif /* defined(TN3270) */ + setconnmode(0); + EmptyTerminal(); /* Flush the path to the tty */ + setcommandmode(); +} + + void +Exit(returnCode) + int returnCode; +{ + SetForExit(); + exit(returnCode); +} + + void +ExitString(string, returnCode) + char *string; + int returnCode; +{ + SetForExit(); + fwrite(string, 1, strlen(string), stderr); + exit(returnCode); +} diff --git a/usr.bin/tftp/Makefile b/usr.bin/tftp/Makefile new file mode 100644 index 0000000..d91ba61 --- /dev/null +++ b/usr.bin/tftp/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tftp +SRCS= main.c tftp.c tftpsubs.c + +.include diff --git a/usr.bin/tftp/extern.h b/usr.bin/tftp/extern.h new file mode 100644 index 0000000..9174cb1 --- /dev/null +++ b/usr.bin/tftp/extern.h @@ -0,0 +1,37 @@ +/* + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +void recvfile __P((int, char *, char *)); +void sendfile __P((int, char *, char *)); diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c new file mode 100644 index 0000000..f99e7f6 --- /dev/null +++ b/usr.bin/tftp/main.c @@ -0,0 +1,733 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* Many bug fixes are from Jim Guyton */ + +/* + * TFTP User Program -- Command Interface. + */ +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +#define TIMEOUT 5 /* secs between rexmt's */ + +struct sockaddr_in peeraddr; +int f; +short port; +int trace; +int verbose; +int connected; +char mode[32]; +char line[200]; +int margc; +char *margv[20]; +char *prompt = "tftp"; +jmp_buf toplevel; +void intr(); +struct servent *sp; + +void get __P((int, char **)); +void help __P((int, char **)); +void modecmd __P((int, char **)); +void put __P((int, char **)); +void quit __P((int, char **)); +void setascii __P((int, char **)); +void setbinary __P((int, char **)); +void setpeer __P((int, char **)); +void setrexmt __P((int, char **)); +void settimeout __P((int, char **)); +void settrace __P((int, char **)); +void setverbose __P((int, char **)); +void status __P((int, char **)); + +static __dead void command __P((void)); + +static void getusage __P((char *)); +static void makeargv __P((void)); +static void putusage __P((char *)); +static void settftpmode __P((char *)); + +#define HELPINDENT (sizeof("connect")) + +struct cmd { + char *name; + char *help; + void (*handler) __P((int, char **)); +}; + +char vhelp[] = "toggle verbose mode"; +char thelp[] = "toggle packet tracing"; +char chelp[] = "connect to remote tftp"; +char qhelp[] = "exit tftp"; +char hhelp[] = "print help information"; +char shelp[] = "send file"; +char rhelp[] = "receive file"; +char mhelp[] = "set file transfer mode"; +char sthelp[] = "show current status"; +char xhelp[] = "set per-packet retransmission timeout"; +char ihelp[] = "set total retransmission timeout"; +char ashelp[] = "set mode to netascii"; +char bnhelp[] = "set mode to octet"; + +struct cmd cmdtab[] = { + { "connect", chelp, setpeer }, + { "mode", mhelp, modecmd }, + { "put", shelp, put }, + { "get", rhelp, get }, + { "quit", qhelp, quit }, + { "verbose", vhelp, setverbose }, + { "trace", thelp, settrace }, + { "status", sthelp, status }, + { "binary", bnhelp, setbinary }, + { "ascii", ashelp, setascii }, + { "rexmt", xhelp, setrexmt }, + { "timeout", ihelp, settimeout }, + { "?", hhelp, help }, + { 0 } +}; + +struct cmd *getcmd(); +char *tail(); +char *index(); +char *rindex(); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + + sp = getservbyname("tftp", "udp"); + if (sp == 0) { + fprintf(stderr, "tftp: udp/tftp: unknown service\n"); + exit(1); + } + f = socket(AF_INET, SOCK_DGRAM, 0); + if (f < 0) { + perror("tftp: socket"); + exit(3); + } + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + perror("tftp: bind"); + exit(1); + } + strcpy(mode, "netascii"); + signal(SIGINT, intr); + if (argc > 1) { + if (setjmp(toplevel) != 0) + exit(0); + setpeer(argc, argv); + } + if (setjmp(toplevel) != 0) + (void)putchar('\n'); + command(); +} + +char hostname[100]; + +void +setpeer(argc, argv) + int argc; + char *argv[]; +{ + struct hostent *host; + + if (argc < 2) { + strcpy(line, "Connect "); + printf("(to) "); + gets(&line[strlen(line)]); + makeargv(); + argc = margc; + argv = margv; + } + if (argc > 3) { + printf("usage: %s host-name [port]\n", argv[0]); + return; + } + host = gethostbyname(argv[1]); + if (host) { + peeraddr.sin_family = host->h_addrtype; + bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length); + strcpy(hostname, host->h_name); + } else { + peeraddr.sin_family = AF_INET; + peeraddr.sin_addr.s_addr = inet_addr(argv[1]); + if (peeraddr.sin_addr.s_addr == -1) { + connected = 0; + printf("%s: unknown host\n", argv[1]); + return; + } + strcpy(hostname, argv[1]); + } + port = sp->s_port; + if (argc == 3) { + port = atoi(argv[2]); + if (port < 0) { + printf("%s: bad port number\n", argv[2]); + connected = 0; + return; + } + port = htons(port); + } + connected = 1; +} + +struct modes { + char *m_name; + char *m_mode; +} modes[] = { + { "ascii", "netascii" }, + { "netascii", "netascii" }, + { "binary", "octet" }, + { "image", "octet" }, + { "octet", "octet" }, +/* { "mail", "mail" }, */ + { 0, 0 } +}; + +void +modecmd(argc, argv) + int argc; + char *argv[]; +{ + register struct modes *p; + char *sep; + + if (argc < 2) { + printf("Using %s mode to transfer files.\n", mode); + return; + } + if (argc == 2) { + for (p = modes; p->m_name; p++) + if (strcmp(argv[1], p->m_name) == 0) + break; + if (p->m_name) { + settftpmode(p->m_mode); + return; + } + printf("%s: unknown mode\n", argv[1]); + /* drop through and print usage message */ + } + + printf("usage: %s [", argv[0]); + sep = " "; + for (p = modes; p->m_name; p++) { + printf("%s%s", sep, p->m_name); + if (*sep == ' ') + sep = " | "; + } + printf(" ]\n"); + return; +} + +void +setbinary(argc, argv) + int argc; + char *argv[]; +{ + + settftpmode("octet"); +} + +void +setascii(argc, argv) + int argc; + char *argv[]; +{ + + settftpmode("netascii"); +} + +static void +settftpmode(newmode) + char *newmode; +{ + strcpy(mode, newmode); + if (verbose) + printf("mode set to %s\n", mode); +} + + +/* + * Send file(s). + */ +void +put(argc, argv) + int argc; + char *argv[]; +{ + int fd; + register int n; + register char *cp, *targ; + + if (argc < 2) { + strcpy(line, "send "); + printf("(file) "); + gets(&line[strlen(line)]); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + putusage(argv[0]); + return; + } + targ = argv[argc - 1]; + if (index(argv[argc - 1], ':')) { + char *cp; + struct hostent *hp; + + for (n = 1; n < argc - 1; n++) + if (index(argv[n], ':')) { + putusage(argv[0]); + return; + } + cp = argv[argc - 1]; + targ = index(cp, ':'); + *targ++ = 0; + hp = gethostbyname(cp); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", cp); + herror((char *)NULL); + return; + } + bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length); + peeraddr.sin_family = hp->h_addrtype; + connected = 1; + strcpy(hostname, hp->h_name); + } + if (!connected) { + printf("No target machine specified.\n"); + return; + } + if (argc < 4) { + cp = argc == 2 ? tail(targ) : argv[1]; + fd = open(cp, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + return; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + cp, hostname, targ, mode); + peeraddr.sin_port = port; + sendfile(fd, targ, mode); + return; + } + /* this assumes the target is a directory */ + /* on a remote unix system. hmmmm. */ + cp = index(targ, '\0'); + *cp++ = '/'; + for (n = 1; n < argc - 1; n++) { + strcpy(cp, tail(argv[n])); + fd = open(argv[n], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(argv[n]); + continue; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + argv[n], hostname, targ, mode); + peeraddr.sin_port = port; + sendfile(fd, targ, mode); + } +} + +static void +putusage(s) + char *s; +{ + printf("usage: %s file ... host:target, or\n", s); + printf(" %s file ... target (when already connected)\n", s); +} + +/* + * Receive file(s). + */ +void +get(argc, argv) + int argc; + char *argv[]; +{ + int fd; + register int n; + register char *cp; + char *src; + + if (argc < 2) { + strcpy(line, "get "); + printf("(files) "); + gets(&line[strlen(line)]); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + getusage(argv[0]); + return; + } + if (!connected) { + for (n = 1; n < argc ; n++) + if (index(argv[n], ':') == 0) { + getusage(argv[0]); + return; + } + } + for (n = 1; n < argc ; n++) { + src = index(argv[n], ':'); + if (src == NULL) + src = argv[n]; + else { + struct hostent *hp; + + *src++ = 0; + hp = gethostbyname(argv[n]); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", argv[n]); + herror((char *)NULL); + continue; + } + bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, + hp->h_length); + peeraddr.sin_family = hp->h_addrtype; + connected = 1; + strcpy(hostname, hp->h_name); + } + if (argc < 4) { + cp = argc == 3 ? argv[2] : tail(src); + fd = creat(cp, 0644); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + return; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode); + peeraddr.sin_port = port; + recvfile(fd, src, mode); + break; + } + cp = tail(src); /* new .. jdg */ + fd = creat(cp, 0644); + if (fd < 0) { + fprintf(stderr, "tftp: "); perror(cp); + continue; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode); + peeraddr.sin_port = port; + recvfile(fd, src, mode); + } +} + +static void +getusage(s) + char *s; +{ + printf("usage: %s host:file host:file ... file, or\n", s); + printf(" %s file file ... file if connected\n", s); +} + +int rexmtval = TIMEOUT; + +void +setrexmt(argc, argv) + int argc; + char *argv[]; +{ + int t; + + if (argc < 2) { + strcpy(line, "Rexmt-timeout "); + printf("(value) "); + gets(&line[strlen(line)]); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + rexmtval = t; +} + +int maxtimeout = 5 * TIMEOUT; + +void +settimeout(argc, argv) + int argc; + char *argv[]; +{ + int t; + + if (argc < 2) { + strcpy(line, "Maximum-timeout "); + printf("(value) "); + gets(&line[strlen(line)]); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + maxtimeout = t; +} + +void +status(argc, argv) + int argc; + char *argv[]; +{ + if (connected) + printf("Connected to %s.\n", hostname); + else + printf("Not connected.\n"); + printf("Mode: %s Verbose: %s Tracing: %s\n", mode, + verbose ? "on" : "off", trace ? "on" : "off"); + printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", + rexmtval, maxtimeout); +} + +void +intr() +{ + + signal(SIGALRM, SIG_IGN); + alarm(0); + longjmp(toplevel, -1); +} + +char * +tail(filename) + char *filename; +{ + register char *s; + + while (*filename) { + s = rindex(filename, '/'); + if (s == NULL) + break; + if (s[1]) + return (s + 1); + *s = '\0'; + } + return (filename); +} + +/* + * Command parser. + */ +static __dead void +command() +{ + register struct cmd *c; + + for (;;) { + printf("%s> ", prompt); + if (gets(line) == 0) { + if (feof(stdin)) { + exit(0); + } else { + continue; + } + } + if (line[0] == 0) + continue; + makeargv(); + if (margc == 0) + continue; + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + (*c->handler)(margc, margv); + } +} + +struct cmd * +getcmd(name) + register char *name; +{ + register char *p, *q; + register struct cmd *c, *found; + register int nmatches, longest; + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; (p = c->name) != NULL; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); +} + +/* + * Slice a string up into argc/argv. + */ +static void +makeargv() +{ + register char *cp; + register char **argp = margv; + + margc = 0; + for (cp = line; *cp;) { + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *argp++ = cp; + margc += 1; + while (*cp != '\0' && !isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *cp++ = '\0'; + } + *argp++ = 0; +} + +void +quit(argc, argv) + int argc; + char *argv[]; +{ + + exit(0); +} + +/* + * Help command. + */ +void +help(argc, argv) + int argc; + char *argv[]; +{ + register struct cmd *c; + + if (argc == 1) { + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->name; c++) + printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); + return; + } + while (--argc > 0) { + register char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%s\n", c->help); + } +} + +void +settrace(argc, argv) + int argc; + char **argv; +{ + trace = !trace; + printf("Packet tracing %s.\n", trace ? "on" : "off"); +} + +void +setverbose(argc, argv) + int argc; + char **argv; +{ + verbose = !verbose; + printf("Verbose mode %s.\n", verbose ? "on" : "off"); +} diff --git a/usr.bin/tftp/tftp.1 b/usr.bin/tftp/tftp.1 new file mode 100644 index 0000000..b2c5a16 --- /dev/null +++ b/usr.bin/tftp/tftp.1 @@ -0,0 +1,173 @@ +.\" Copyright (c) 1990, 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. +.\" +.\" @(#)tftp.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt TFTP 1 +.Os BSD 4.3 +.Sh NAME +.Nm tftp +.Nd trivial file transfer program +.Sh SYNOPSIS +.Nm tftp +.Op Ar host +.Sh DESCRIPTION +.Nm Tftp +is the user interface to the Internet +.Tn TFTP +(Trivial File Transfer Protocol), +which allows users to transfer files to and from a remote machine. +The remote +.Ar host +may be specified on the command line, in which case +.Nm tftp +uses +.Ar host +as the default host for future transfers (see the +.Cm connect +command below). +.Sh COMMANDS +Once +.Nm tftp +is running, it issues the prompt +.LI tftp> +and recognizes the following commands: +.Pp +.Bl -tag -width verbose -compact +.It Cm \&? Ar command-name ... +Print help information. +.Pp +.It Cm ascii +Shorthand for "mode ascii" +.Pp +.It Cm binary +Shorthand for "mode binary" +.Pp +.It Cm connect Ar host-name Op Ar port +Set the +.Ar host +(and optionally +.Ar port ) +for transfers. +Note that the +.Tn TFTP +protocol, unlike the +.Tn FTP +protocol, +does not maintain connections between transfers; thus, the +.Cm connect +command does not actually create a connection, +but merely remembers what host is to be used for transfers. +You do not have to use the +.Cm connect +command; the remote host can be specified as part of the +.Cm get +or +.Cm put +commands. +.Pp +.It Cm get Ar filename +.It Cm get Ar remotename localname +.It Cm get Ar file1 file2 ... fileN +Get a file or set of files from the specified +.Ar sources . +.Ar Source +can be in one of two forms: +a filename on the remote host, if the host has already been specified, +or a string of the form +.Ar hosts:filename +to specify both a host and filename at the same time. +If the latter form is used, +the last hostname specified becomes the default for future transfers. +.Pp +.It Cm mode Ar transfer-mode +Set the mode for transfers; +.Ar transfer-mode +may be one of +.Em ascii +or +.Em binary . +The default is +.Em ascii . +.Pp +.It Cm put Ar file +.It Cm put Ar localfile remotefile +.It Cm put Ar file1 file2 ... fileN remote-directory +Put a file or set of files to the specified +remote file or directory. +The destination +can be in one of two forms: +a filename on the remote host, if the host has already been specified, +or a string of the form +.Ar hosts:filename +to specify both a host and filename at the same time. +If the latter form is used, +the hostname specified becomes the default for future transfers. +If the remote-directory form is used, the remote host is +assumed to be a +.Tn UNIX +machine. +.Pp +.It Cm quit +Exit +.Nm tftp . +An end of file also exits. +.Pp +.It Cm rexmt Ar retransmission-timeout +Set the per-packet retransmission timeout, in seconds. +.Pp +.It Cm status +Show current status. +.Pp +.It Cm timeout Ar total-transmission-timeout +Set the total transmission timeout, in seconds. +.Pp +.It Cm trace +Toggle packet tracing. +.Pp +.It Cm verbose +Toggle verbose mode. +.El +.Sh BUGS +.Pp +Because there is no user-login or validation within +the +.Tn TFTP +protocol, the remote site will probably have some +sort of file-access restrictions in place. The +exact methods are specific to each site and therefore +difficult to document here. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/tftp/tftp.c b/usr.bin/tftp/tftp.c new file mode 100644 index 0000000..2ca4001 --- /dev/null +++ b/usr.bin/tftp/tftp.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* Many bug fixes are from Jim Guyton */ + +/* + * TFTP User Program -- Protocol Machines + */ +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include "extern.h" +#include "tftpsubs.h" + +extern int errno; + +extern struct sockaddr_in peeraddr; /* filled in by main */ +extern int f; /* the opened socket */ +extern int trace; +extern int verbose; +extern int rexmtval; +extern int maxtimeout; + +#define PKTSIZE SEGSIZE+4 +char ackbuf[PKTSIZE]; +int timeout; +jmp_buf toplevel; +jmp_buf timeoutbuf; + +static void nak __P((int)); +static int makerequest __P((int, const char *, struct tftphdr *, const char *)); +static void printstats __P((const char *, unsigned long)); +static void startclock __P((void)); +static void stopclock __P((void)); +static void timer __P((int)); +static void tpacket __P((const char *, struct tftphdr *, int)); + +/* + * Send the requested file. + */ +void +sendfile(fd, name, mode) + int fd; + char *name; + char *mode; +{ + register struct tftphdr *ap; /* data and ack packets */ + struct tftphdr *r_init(), *dp; + register int n; + volatile int block, size, convert; + volatile unsigned long amount; + struct sockaddr_in from; + int fromlen; + FILE *file; + + startclock(); /* start stat's clock */ + dp = r_init(); /* reset fillbuf/read-ahead code */ + ap = (struct tftphdr *)ackbuf; + file = fdopen(fd, "r"); + convert = !strcmp(mode, "netascii"); + block = 0; + amount = 0; + + signal(SIGALRM, timer); + do { + if (block == 0) + size = makerequest(WRQ, name, dp, mode) - 4; + else { + /* size = read(fd, dp->th_data, SEGSIZE); */ + size = readit(file, &dp, convert); + if (size < 0) { + nak(errno + 100); + break; + } + dp->th_opcode = htons((u_short)DATA); + dp->th_block = htons((u_short)block); + } + timeout = 0; + (void) setjmp(timeoutbuf); +send_data: + if (trace) + tpacket("sent", dp, size + 4); + n = sendto(f, dp, size + 4, 0, + (struct sockaddr *)&peeraddr, sizeof(peeraddr)); + if (n != size + 4) { + perror("tftp: sendto"); + goto abort; + } + read_ahead(file, convert); + for ( ; ; ) { + alarm(rexmtval); + do { + fromlen = sizeof(from); + n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, + (struct sockaddr *)&from, &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + peeraddr.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", ap, n); + /* should verify packet came from server */ + ap->th_opcode = ntohs(ap->th_opcode); + ap->th_block = ntohs(ap->th_block); + if (ap->th_opcode == ERROR) { + printf("Error code %d: %s\n", ap->th_code, + ap->th_msg); + goto abort; + } + if (ap->th_opcode == ACK) { + int j; + + if (ap->th_block == block) { + break; + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", + j); + } + if (ap->th_block == (block-1)) { + goto send_data; + } + } + } + if (block > 0) + amount += size; + block++; + } while (size == SEGSIZE || block == 1); +abort: + fclose(file); + stopclock(); + if (amount > 0) + printstats("Sent", amount); +} + +/* + * Receive a file. + */ +void +recvfile(fd, name, mode) + int fd; + char *name; + char *mode; +{ + register struct tftphdr *ap; + struct tftphdr *dp, *w_init(); + register int n; + volatile int block, size, firsttrip; + volatile unsigned long amount; + struct sockaddr_in from; + int fromlen; + FILE *file; + volatile int convert; /* true if converting crlf -> lf */ + + startclock(); + dp = w_init(); + ap = (struct tftphdr *)ackbuf; + file = fdopen(fd, "w"); + convert = !strcmp(mode, "netascii"); + block = 1; + firsttrip = 1; + amount = 0; + + signal(SIGALRM, timer); + do { + if (firsttrip) { + size = makerequest(RRQ, name, ap, mode); + firsttrip = 0; + } else { + ap->th_opcode = htons((u_short)ACK); + ap->th_block = htons((u_short)(block)); + size = 4; + block++; + } + timeout = 0; + (void) setjmp(timeoutbuf); +send_ack: + if (trace) + tpacket("sent", ap, size); + if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != size) { + alarm(0); + perror("tftp: sendto"); + goto abort; + } + write_behind(file, convert); + for ( ; ; ) { + alarm(rexmtval); + do { + fromlen = sizeof(from); + n = recvfrom(f, dp, PKTSIZE, 0, + (struct sockaddr *)&from, &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + peeraddr.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", dp, n); + /* should verify client address */ + dp->th_opcode = ntohs(dp->th_opcode); + dp->th_block = ntohs(dp->th_block); + if (dp->th_opcode == ERROR) { + printf("Error code %d: %s\n", dp->th_code, + dp->th_msg); + goto abort; + } + if (dp->th_opcode == DATA) { + int j; + + if (dp->th_block == block) { + break; /* have next packet */ + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", j); + } + if (dp->th_block == (block-1)) { + goto send_ack; /* resend ack */ + } + } + } + /* size = write(fd, dp->th_data, n - 4); */ + size = writeit(file, &dp, n - 4, convert); + if (size < 0) { + nak(errno + 100); + break; + } + amount += size; + } while (size == SEGSIZE); +abort: /* ok to ack, since user */ + ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ + ap->th_block = htons((u_short)block); + (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)); + write_behind(file, convert); /* flush last buffer */ + fclose(file); + stopclock(); + if (amount > 0) + printstats("Received", amount); +} + +static int +makerequest(request, name, tp, mode) + int request; + const char *name; + struct tftphdr *tp; + const char *mode; +{ + register char *cp; + + tp->th_opcode = htons((u_short)request); + cp = tp->th_stuff; + strcpy(cp, name); + cp += strlen(name); + *cp++ = '\0'; + strcpy(cp, mode); + cp += strlen(mode); + *cp++ = '\0'; + return (cp - (char *)tp); +} + +struct errmsg { + int e_code; + char *e_msg; +} errmsgs[] = { + { EUNDEF, "Undefined error code" }, + { ENOTFOUND, "File not found" }, + { EACCESS, "Access violation" }, + { ENOSPACE, "Disk full or allocation exceeded" }, + { EBADOP, "Illegal TFTP operation" }, + { EBADID, "Unknown transfer ID" }, + { EEXISTS, "File already exists" }, + { ENOUSER, "No such user" }, + { -1, 0 } +}; + +/* + * Send a nak packet (error message). + * Error code passed in is one of the + * standard TFTP codes, or a UNIX errno + * offset by 100. + */ +static void +nak(error) + int error; +{ + register struct errmsg *pe; + register struct tftphdr *tp; + int length; + char *strerror(); + + tp = (struct tftphdr *)ackbuf; + tp->th_opcode = htons((u_short)ERROR); + tp->th_code = htons((u_short)error); + for (pe = errmsgs; pe->e_code >= 0; pe++) + if (pe->e_code == error) + break; + if (pe->e_code < 0) { + pe->e_msg = strerror(error - 100); + tp->th_code = EUNDEF; + } + strcpy(tp->th_msg, pe->e_msg); + length = strlen(pe->e_msg) + 4; + if (trace) + tpacket("sent", tp, length); + if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != length) + perror("nak"); +} + +static void +tpacket(s, tp, n) + const char *s; + struct tftphdr *tp; + int n; +{ + static char *opcodes[] = + { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; + register char *cp, *file; + u_short op = ntohs(tp->th_opcode); + char *index(); + + if (op < RRQ || op > ERROR) + printf("%s opcode=%x ", s, op); + else + printf("%s %s ", s, opcodes[op]); + switch (op) { + + case RRQ: + case WRQ: + n -= 2; + file = cp = tp->th_stuff; + cp = index(cp, '\0'); + printf("\n", file, cp + 1); + break; + + case DATA: + printf("\n", ntohs(tp->th_block), n - 4); + break; + + case ACK: + printf("\n", ntohs(tp->th_block)); + break; + + case ERROR: + printf("\n", ntohs(tp->th_code), tp->th_msg); + break; + } +} + +struct timeval tstart; +struct timeval tstop; + +static void +startclock() +{ + + (void)gettimeofday(&tstart, NULL); +} + +static void +stopclock() +{ + + (void)gettimeofday(&tstop, NULL); +} + +static void +printstats(direction, amount) + const char *direction; + unsigned long amount; +{ + double delta; + /* compute delta in 1/10's second units */ + delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - + ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); + delta = delta/10.; /* back to seconds */ + printf("%s %d bytes in %.1f seconds", direction, amount, delta); + if (verbose) + printf(" [%.0f bits/sec]", (amount*8.)/delta); + putchar('\n'); +} + +static void +timer(sig) + int sig; +{ + + timeout += rexmtval; + if (timeout >= maxtimeout) { + printf("Transfer timed out.\n"); + longjmp(toplevel, -1); + } + longjmp(timeoutbuf, 1); +} diff --git a/usr.bin/tftp/tftpsubs.c b/usr.bin/tftp/tftpsubs.c new file mode 100644 index 0000000..a143602 --- /dev/null +++ b/usr.bin/tftp/tftpsubs.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* Simple minded read-ahead/write-behind subroutines for tftp user and + server. Written originally with multiple buffers in mind, but current + implementation has two buffer logic wired in. + + Todo: add some sort of final error check so when the write-buffer + is finally flushed, the caller can detect if the disk filled up + (or had an i/o error) and return a nak to the other side. + + Jim Guyton 10/85 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "tftpsubs.h" + +#define PKTSIZE SEGSIZE+4 /* should be moved to tftp.h */ + +struct bf { + int counter; /* size of data in buffer, or flag */ + char buf[PKTSIZE]; /* room for data packet */ +} bfs[2]; + + /* Values for bf.counter */ +#define BF_ALLOC -3 /* alloc'd but not yet filled */ +#define BF_FREE -2 /* free */ +/* [-1 .. SEGSIZE] = size of data in the data buffer */ + +static int nextone; /* index of next buffer to use */ +static int current; /* index of buffer in use */ + + /* control flags for crlf conversions */ +int newline = 0; /* fillbuf: in middle of newline expansion */ +int prevchar = -1; /* putbuf: previous char (cr check) */ + +static struct tftphdr *rw_init(); + +struct tftphdr *w_init() { return rw_init(0); } /* write-behind */ +struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */ + +static struct tftphdr * +rw_init(x) /* init for either read-ahead or write-behind */ + int x; /* zero for write-behind, one for read-head */ +{ + newline = 0; /* init crlf flag */ + prevchar = -1; + bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ + current = 0; + bfs[1].counter = BF_FREE; + nextone = x; /* ahead or behind? */ + return (struct tftphdr *)bfs[0].buf; +} + + +/* Have emptied current buffer by sending to net and getting ack. + Free it and return next buffer filled with data. + */ +int +readit(file, dpp, convert) + FILE *file; /* file opened for read */ + struct tftphdr **dpp; + int convert; /* if true, convert to ascii */ +{ + struct bf *b; + + bfs[current].counter = BF_FREE; /* free old one */ + current = !current; /* "incr" current */ + + b = &bfs[current]; /* look at new buffer */ + if (b->counter == BF_FREE) /* if it's empty */ + read_ahead(file, convert); /* fill it */ +/* assert(b->counter != BF_FREE);*//* check */ + *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */ + return b->counter; +} + +/* + * fill the input buffer, doing ascii conversions if requested + * conversions are lf -> cr,lf and cr -> cr, nul + */ +void +read_ahead(file, convert) + FILE *file; /* file opened for read */ + int convert; /* if true, convert to ascii */ +{ + register int i; + register char *p; + register int c; + struct bf *b; + struct tftphdr *dp; + + b = &bfs[nextone]; /* look at "next" buffer */ + if (b->counter != BF_FREE) /* nop if not free */ + return; + nextone = !nextone; /* "incr" next buffer ptr */ + + dp = (struct tftphdr *)b->buf; + + if (convert == 0) { + b->counter = read(fileno(file), dp->th_data, SEGSIZE); + return; + } + + p = dp->th_data; + for (i = 0 ; i < SEGSIZE; i++) { + if (newline) { + if (prevchar == '\n') + c = '\n'; /* lf to cr,lf */ + else c = '\0'; /* cr to cr,nul */ + newline = 0; + } + else { + c = getc(file); + if (c == EOF) break; + if (c == '\n' || c == '\r') { + prevchar = c; + c = '\r'; + newline = 1; + } + } + *p++ = c; + } + b->counter = (int)(p - dp->th_data); +} + +/* Update count associated with the buffer, get new buffer + from the queue. Calls write_behind only if next buffer not + available. + */ +int +writeit(file, dpp, ct, convert) + FILE *file; + struct tftphdr **dpp; + int ct, convert; +{ + bfs[current].counter = ct; /* set size of data to write */ + current = !current; /* switch to other buffer */ + if (bfs[current].counter != BF_FREE) /* if not free */ + (void)write_behind(file, convert); /* flush it */ + bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ + *dpp = (struct tftphdr *)bfs[current].buf; + return ct; /* this is a lie of course */ +} + +/* + * Output a buffer to a file, converting from netascii if requested. + * CR,NUL -> CR and CR,LF => LF. + * Note spec is undefined if we get CR as last byte of file or a + * CR followed by anything else. In this case we leave it alone. + */ +int +write_behind(file, convert) + FILE *file; + int convert; +{ + char *buf; + int count; + register int ct; + register char *p; + register int c; /* current character */ + struct bf *b; + struct tftphdr *dp; + + b = &bfs[nextone]; + if (b->counter < -1) /* anything to flush? */ + return 0; /* just nop if nothing to do */ + + count = b->counter; /* remember byte count */ + b->counter = BF_FREE; /* reset flag */ + dp = (struct tftphdr *)b->buf; + nextone = !nextone; /* incr for next time */ + buf = dp->th_data; + + if (count <= 0) return -1; /* nak logic? */ + + if (convert == 0) + return write(fileno(file), buf, count); + + p = buf; + ct = count; + while (ct--) { /* loop over the buffer */ + c = *p++; /* pick up a character */ + if (prevchar == '\r') { /* if prev char was cr */ + if (c == '\n') /* if have cr,lf then just */ + fseek(file, -1, 1); /* smash lf on top of the cr */ + else + if (c == '\0') /* if have cr,nul then */ + goto skipit; /* just skip over the putc */ + /* else just fall through and allow it */ + } + putc(c, file); +skipit: + prevchar = c; + } + return count; +} + + +/* When an error has occurred, it is possible that the two sides + * are out of synch. Ie: that what I think is the other side's + * response to packet N is really their response to packet N-1. + * + * So, to try to prevent that, we flush all the input queued up + * for us on the network connection on our host. + * + * We return the number of packets we flushed (mostly for reporting + * when trace is active). + */ + +int +synchnet(f) + int f; /* socket to flush */ +{ + int i, j = 0; + char rbuf[PKTSIZE]; + struct sockaddr_in from; + int fromlen; + + while (1) { + (void) ioctl(f, FIONREAD, &i); + if (i) { + j++; + fromlen = sizeof from; + (void) recvfrom(f, rbuf, sizeof (rbuf), 0, + (struct sockaddr *)&from, &fromlen); + } else { + return(j); + } + } +} diff --git a/usr.bin/tftp/tftpsubs.h b/usr.bin/tftp/tftpsubs.h new file mode 100644 index 0000000..1733bf1 --- /dev/null +++ b/usr.bin/tftp/tftpsubs.h @@ -0,0 +1,48 @@ +/* + * 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. + * + * @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Prototypes for read-ahead/write-behind subroutines for tftp user and + * server. + */ +struct tftphdr *r_init __P((void)); +void read_ahead __P((FILE *, int)); +int readit __P((FILE *, struct tftphdr **, int)); + +int synchnet __P((int)); + +struct tftphdr *w_init __P((void)); +int write_behind __P((FILE *, int)); +int writeit __P((FILE *, struct tftphdr **, int, int)); diff --git a/usr.bin/time/Makefile b/usr.bin/time/Makefile new file mode 100644 index 0000000..ae649c7 --- /dev/null +++ b/usr.bin/time/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= time + +.include diff --git a/usr.bin/time/time.1 b/usr.bin/time/time.1 new file mode 100644 index 0000000..f68c6f4 --- /dev/null +++ b/usr.bin/time/time.1 @@ -0,0 +1,99 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)time.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TIME 1 +.Os BSD 4 +.Sh NAME +.Nm time +.Nd time command execution +.Sh SYNOPSIS +.Nm time +.Op Fl l +.Ar command +.Sh DESCRIPTION +The +.Nm time +utility +executes and +times +.Ar command +by initiating a timer and passing the +.Ar command +to the +shell. +After the +.Ar command +finishes, +.Nm time +writes to the standard error stream, +(in seconds): +the total time elapsed, +time consumed by system overhead, +and the time used to execute the +.Ar command +process. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl l +The contents of the +.Em rusage +structure are printed as well. +.El +.Pp +The +.Xr csh 1 +has its own and syntactically different builtin version of +.Nm time. +The command described here +is available as +.Pa /usr/bin/time +to +.Xr csh +users. +.Sh BUGS +The granularity of seconds on micro processors is crude and +can result in times being reported for CPU usage which are too large by +a second. +.Sh SEE ALSO +.Xr csh 1 +.Sh FILES +.Bl -tag -width /usr/include/sys/h/resource.h -compact +.It Pa /usr/include/sys/h/resource.h +.El +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/time/time.c b/usr.bin/time/time.c new file mode 100644 index 0000000..72c3766 --- /dev/null +++ b/usr.bin/time/time.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1987, 1988, 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 copyright[] = +"@(#) Copyright (c) 1987, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + register int pid; + int ch, status, lflag; + struct timeval before, after; + struct rusage ru; + + lflag = 0; + while ((ch = getopt(argc, argv, "l")) != EOF) + switch((char)ch) { + case 'l': + lflag = 1; + break; + case '?': + default: + fprintf(stderr, "usage: time [-l] command.\n"); + exit(1); + } + + if (!(argc -= optind)) + exit(0); + argv += optind; + + gettimeofday(&before, (struct timezone *)NULL); + switch(pid = vfork()) { + case -1: /* error */ + perror("time"); + exit(1); + /* NOTREACHED */ + case 0: /* child */ + execvp(*argv, argv); + perror(*argv); + _exit(1); + /* NOTREACHED */ + } + /* parent */ + (void)signal(SIGINT, SIG_IGN); + (void)signal(SIGQUIT, SIG_IGN); + while (wait3(&status, 0, &ru) != pid); /* XXX use waitpid */ + gettimeofday(&after, (struct timezone *)NULL); + if (status&0377) + fprintf(stderr, "Command terminated abnormally.\n"); + after.tv_sec -= before.tv_sec; + after.tv_usec -= before.tv_usec; + if (after.tv_usec < 0) + after.tv_sec--, after.tv_usec += 1000000; + fprintf(stderr, "%9ld.%02ld real ", after.tv_sec, after.tv_usec/10000); + fprintf(stderr, "%9ld.%02ld user ", + ru.ru_utime.tv_sec, ru.ru_utime.tv_usec/10000); + fprintf(stderr, "%9ld.%02ld sys\n", + ru.ru_stime.tv_sec, ru.ru_stime.tv_usec/10000); + if (lflag) { + int hz = 100; /* XXX */ + long ticks; + + ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + + hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; + fprintf(stderr, "%10ld %s\n", + ru.ru_maxrss, "maximum resident set size"); + fprintf(stderr, "%10ld %s\n", + ru.ru_ixrss / ticks, "average shared memory size"); + fprintf(stderr, "%10ld %s\n", + ru.ru_idrss / ticks, "average unshared data size"); + fprintf(stderr, "%10ld %s\n", + ru.ru_isrss / ticks, "average unshared stack size"); + fprintf(stderr, "%10ld %s\n", + ru.ru_minflt, "page reclaims"); + fprintf(stderr, "%10ld %s\n", + ru.ru_majflt, "page faults"); + fprintf(stderr, "%10ld %s\n", + ru.ru_nswap, "swaps"); + fprintf(stderr, "%10ld %s\n", + ru.ru_inblock, "block input operations"); + fprintf(stderr, "%10ld %s\n", + ru.ru_oublock, "block output operations"); + fprintf(stderr, "%10ld %s\n", + ru.ru_msgsnd, "messages sent"); + fprintf(stderr, "%10ld %s\n", + ru.ru_msgrcv, "messages received"); + fprintf(stderr, "%10ld %s\n", + ru.ru_nsignals, "signals received"); + fprintf(stderr, "%10ld %s\n", + ru.ru_nvcsw, "voluntary context switches"); + fprintf(stderr, "%10ld %s\n", + ru.ru_nivcsw, "involuntary context switches"); + } + exit (status>>8); +} diff --git a/usr.bin/tip/Makefile b/usr.bin/tip/Makefile new file mode 100644 index 0000000..21514ed5 --- /dev/null +++ b/usr.bin/tip/Makefile @@ -0,0 +1,52 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# +# Files are: +# /etc/remote remote host description file +# /etc/phones phone number file, owned by ${OWNER} and +# mode 6?? +# /var/log/aculog ACU accounting file, owned by ${OWNER} and +# mode 6?? {if ACULOG defined} +# Presently supports: +# BIZCOMP +# DEC DF02-AC, DF03-AC +# DEC DN-11/Able Quadracall +# HAYES and Hayes emulators +# USR COURIER (2400 baud) +# VENTEL 212+ +# VADIC 831 RS232 adaptor +# VADIC 3451 +# TELEBIT T3000 +# +# Configuration defines: +# DF02, DF03, DN11 ACU's supported +# BIZ1031, BIZ1022, VENTEL, V831, V3451, HAYES, COURIER, T3000 +# ACULOG turn on tip logging of ACU use +# PRISTINE no phone #'s put in ACU log file +# CONNECT worthless command +# DEFBR default baud rate to make connection at +# DEFFS default frame size for FTP buffering of +# writes on local side +# BUFSIZ buffer sizing from stdio, must be fed +# explicitly to remcap.c if not 1024 +# CONNECT enable ~C command (connect pgm to remote) + +PROG= tip +CFLAGS+=-I${.CURDIR} \ + -DDEFBR=1200 -DDEFFS=BUFSIZ -DACULOG -DPRISTINE -DCONNECT \ + -DV831 -DVENTEL -DHAYES -DCOURIER -DT3000 +.PATH: ${.CURDIR}/aculib +BINOWN= uucp +BINGRP= dialer +BINMODE=4510 +LINKS= ${BINDIR}/tip ${BINDIR}/cu +MLINKS= tip.1 cu.1 +SRCS= acu.c acutab.c cmds.c cmdtab.c cu.c hunt.c log.c partab.c \ + remote.c tip.c tipout.c uucplock.c value.c vars.c \ + biz22.c courier.c df.c dn11.c hayes.c t3000.c v3451.c v831.c ventel.c + +# -- acutab is configuration dependent, and so depends on the Makefile +# -- remote.o depends on the Makefile because of DEFBR and DEFFS +# -- log.o depends on the Makefile because of ACULOG +acutab.o log.o remote.o: Makefile + +.include diff --git a/usr.bin/tip/acu.c b/usr.bin/tip/acu.c new file mode 100644 index 0000000..f7bde99 --- /dev/null +++ b/usr.bin/tip/acu.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)acu.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +static acu_t *acu = NOACU; +static int conflag; +static void acuabort(); +static acu_t *acutype(); +static jmp_buf jmpbuf; +/* + * Establish connection for tip + * + * If DU is true, we should dial an ACU whose type is AT. + * The phone numbers are in PN, and the call unit is in CU. + * + * If the PN is an '@', then we consult the PHONES file for + * the phone numbers. This file is /etc/phones, unless overriden + * by an exported shell variable. + * + * The data base files must be in the format: + * host-name[ \t]*phone-number + * with the possibility of multiple phone numbers + * for a single host acting as a rotary (in the order + * found in the file). + */ +char * +connect() +{ + register char *cp = PN; + char *phnum, string[256]; + FILE *fd; + int tried = 0; + + if (!DU) { /* regular connect message */ + if (CM != NOSTR) + pwrite(FD, CM, size(CM)); + logent(value(HOST), "", DV, "call completed"); + return (NOSTR); + } + /* + * @ =>'s use data base in PHONES environment variable + * otherwise, use /etc/phones + */ + signal(SIGINT, acuabort); + signal(SIGQUIT, acuabort); + if (setjmp(jmpbuf)) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + printf("\ncall aborted\n"); + logent(value(HOST), "", "", "call aborted"); + if (acu != NOACU) { + boolean(value(VERBOSE)) = FALSE; + if (conflag) + disconnect(NOSTR); + else + (*acu->acu_abort)(); + } + return ("interrupt"); + } + if ((acu = acutype(AT)) == NOACU) + return ("unknown ACU type"); + if (*cp != '@') { + while (*cp) { + for (phnum = cp; *cp && *cp != ','; cp++) + ; + if (*cp) + *cp++ = '\0'; + + if (conflag = (*acu->acu_dialer)(phnum, CU)) { + if (CM != NOSTR) + pwrite(FD, CM, size(CM)); + logent(value(HOST), phnum, acu->acu_name, + "call completed"); + return (NOSTR); + } else + logent(value(HOST), phnum, acu->acu_name, + "call failed"); + tried++; + } + } else { + if ((fd = fopen(PH, "r")) == NOFILE) { + printf("%s: ", PH); + return ("can't open phone number file"); + } + while (fgets(string, sizeof(string), fd) != NOSTR) { + for (cp = string; !any(*cp, " \t\n"); cp++) + ; + if (*cp == '\n') { + fclose(fd); + return ("unrecognizable host name"); + } + *cp++ = '\0'; + if (strcmp(string, value(HOST))) + continue; + while (any(*cp, " \t")) + cp++; + if (*cp == '\n') { + fclose(fd); + return ("missing phone number"); + } + for (phnum = cp; *cp && *cp != ',' && *cp != '\n'; cp++) + ; + if (*cp) + *cp++ = '\0'; + + if (conflag = (*acu->acu_dialer)(phnum, CU)) { + fclose(fd); + if (CM != NOSTR) + pwrite(FD, CM, size(CM)); + logent(value(HOST), phnum, acu->acu_name, + "call completed"); + return (NOSTR); + } else + logent(value(HOST), phnum, acu->acu_name, + "call failed"); + tried++; + } + fclose(fd); + } + if (!tried) + logent(value(HOST), "", acu->acu_name, "missing phone number"); + else + (*acu->acu_abort)(); + return (tried ? "call failed" : "missing phone number"); +} + +disconnect(reason) + char *reason; +{ + if (!conflag) { + logent(value(HOST), "", DV, "call terminated"); + return; + } + if (reason == NOSTR) { + logent(value(HOST), "", acu->acu_name, "call terminated"); + if (boolean(value(VERBOSE))) + printf("\r\ndisconnecting..."); + } else + logent(value(HOST), "", acu->acu_name, reason); + (*acu->acu_disconnect)(); +} + +static void +acuabort(s) +{ + signal(s, SIG_IGN); + longjmp(jmpbuf, 1); +} + +static acu_t * +acutype(s) + register char *s; +{ + register acu_t *p; + extern acu_t acutable[]; + + for (p = acutable; p->acu_name != '\0'; p++) + if (!strcmp(s, p->acu_name)) + return (p); + return (NOACU); +} diff --git a/usr.bin/tip/aculib/biz22.c b/usr.bin/tip/aculib/biz22.c new file mode 100644 index 0000000..93c5e53 --- /dev/null +++ b/usr.bin/tip/aculib/biz22.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)biz22.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +#define DISCONNECT_CMD "\20\04" /* disconnection string */ + +static void sigALRM(); +static int timeout = 0; +static jmp_buf timeoutbuf; + +/* + * Dial up on a BIZCOMP Model 1022 with either + * tone dialing (mod = "V") + * pulse dialing (mod = "W") + */ +static int +biz_dialer(num, mod) + char *num, *mod; +{ + register int connected = 0; + char cbuf[40]; + static int cmd(), detect(); + + if (boolean(value(VERBOSE))) + printf("\nstarting call..."); + /* + * Disable auto-answer and configure for tone/pulse + * dialing + */ + if (cmd("\02K\r")) { + printf("can't initialize bizcomp..."); + return (0); + } + strcpy(cbuf, "\02.\r"); + cbuf[1] = *mod; + if (cmd(cbuf)) { + printf("can't set dialing mode..."); + return (0); + } + strcpy(cbuf, "\02D"); + strcat(cbuf, num); + strcat(cbuf, "\r"); + write(FD, cbuf, strlen(cbuf)); + if (!detect("7\r")) { + printf("can't get dial tone..."); + return (0); + } + if (boolean(value(VERBOSE))) + printf("ringing..."); + /* + * The reply from the BIZCOMP should be: + * 2 \r or 7 \r failure + * 1 \r success + */ + connected = detect("1\r"); +#ifdef ACULOG + if (timeout) { + char line[80]; + + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "biz1022", line); + } +#endif + if (timeout) + biz22_disconnect(); /* insurance */ + return (connected); +} + +biz22w_dialer(num, acu) + char *num, *acu; +{ + + return (biz_dialer(num, "W")); +} + +biz22f_dialer(num, acu) + char *num, *acu; +{ + + return (biz_dialer(num, "V")); +} + +biz22_disconnect() +{ + int rw = 2; + + write(FD, DISCONNECT_CMD, 4); + sleep(2); + ioctl(FD, TIOCFLUSH, &rw); +} + +biz22_abort() +{ + + write(FD, "\02", 1); +} + +static void +sigALRM() +{ + + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +cmd(s) + register char *s; +{ + sig_t f; + char c; + + write(FD, s, strlen(s)); + f = signal(SIGALRM, sigALRM); + if (setjmp(timeoutbuf)) { + biz22_abort(); + signal(SIGALRM, f); + return (1); + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + signal(SIGALRM, f); + c &= 0177; + return (c != '\r'); +} + +static int +detect(s) + register char *s; +{ + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + while (*s) { + if (setjmp(timeoutbuf)) { + biz22_abort(); + break; + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + c &= 0177; + if (c != *s++) + return (0); + } + signal(SIGALRM, f); + return (timeout == 0); +} diff --git a/usr.bin/tip/aculib/biz31.c b/usr.bin/tip/aculib/biz31.c new file mode 100644 index 0000000..412974d --- /dev/null +++ b/usr.bin/tip/aculib/biz31.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)biz31.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +#define MAXRETRY 3 /* sync up retry count */ +#define DISCONNECT_CMD "\21\25\11\24" /* disconnection string */ + +static void sigALRM(); +static int timeout = 0; +static jmp_buf timeoutbuf; + +/* + * Dial up on a BIZCOMP Model 1031 with either + * tone dialing (mod = "f") + * pulse dialing (mod = "w") + */ +static int +biz_dialer(num, mod) + char *num, *mod; +{ + register int connected = 0; + + if (!bizsync(FD)) { + logent(value(HOST), "", "biz", "out of sync"); + printf("bizcomp out of sync\n"); + delock(uucplock); + exit(0); + } + if (boolean(value(VERBOSE))) + printf("\nstarting call..."); + echo("#\rk$\r$\n"); /* disable auto-answer */ + echo("$>$.$ #\r"); /* tone/pulse dialing */ + echo(mod); + echo("$\r$\n"); + echo("$>$.$ #\re$ "); /* disconnection sequence */ + echo(DISCONNECT_CMD); + echo("\r$\n$\r$\n"); + echo("$>$.$ #\rr$ "); /* repeat dial */ + echo(num); + echo("\r$\n"); + if (boolean(value(VERBOSE))) + printf("ringing..."); + /* + * The reply from the BIZCOMP should be: + * `^G NO CONNECTION\r\n^G\r\n' failure + * ` CONNECTION\r\n^G' success + */ + connected = detect(" "); +#ifdef ACULOG + if (timeout) { + char line[80]; + + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "biz", line); + } +#endif + if (!connected) + flush(" NO CONNECTION\r\n\07\r\n"); + else + flush("CONNECTION\r\n\07"); + if (timeout) + biz31_disconnect(); /* insurance */ + return (connected); +} + +biz31w_dialer(num, acu) + char *num, *acu; +{ + + return (biz_dialer(num, "w")); +} + +biz31f_dialer(num, acu) + char *num, *acu; +{ + + return (biz_dialer(num, "f")); +} + +biz31_disconnect() +{ + + write(FD, DISCONNECT_CMD, 4); + sleep(2); + ioctl(FD, TIOCFLUSH); +} + +biz31_abort() +{ + + write(FD, "\33", 1); +} + +static int +echo(s) + register char *s; +{ + char c; + + while (c = *s++) switch (c) { + + case '$': + read(FD, &c, 1); + s++; + break; + + case '#': + c = *s++; + write(FD, &c, 1); + break; + + default: + write(FD, &c, 1); + read(FD, &c, 1); + } +} + +static void +sigALRM() +{ + + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +detect(s) + register char *s; +{ + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + while (*s) { + if (setjmp(timeoutbuf)) { + printf("\07timeout waiting for reply\n"); + biz31_abort(); + break; + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + if (c != *s++) + break; + } + signal(SIGALRM, f); + return (timeout == 0); +} + +static int +flush(s) + register char *s; +{ + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + while (*s++) { + if (setjmp(timeoutbuf)) + break; + alarm(10); + read(FD, &c, 1); + alarm(0); + } + signal(SIGALRM, f); + timeout = 0; /* guard against disconnection */ +} + +/* + * This convoluted piece of code attempts to get + * the bizcomp in sync. If you don't have the capacity or nread + * call there are gory ways to simulate this. + */ +static int +bizsync(fd) +{ +#ifdef FIOCAPACITY + struct capacity b; +# define chars(b) ((b).cp_nbytes) +# define IOCTL FIOCAPACITY +#endif +#ifdef FIONREAD + long b; +# define chars(b) (b) +# define IOCTL FIONREAD +#endif + register int already = 0; + char buf[10]; + +retry: + if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0 && chars(b) > 0) + ioctl(fd, TIOCFLUSH); + write(fd, "\rp>\r", 4); + sleep(1); + if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0) { + if (chars(b) != 10) { + nono: + if (already > MAXRETRY) + return (0); + write(fd, DISCONNECT_CMD, 4); + sleep(2); + already++; + goto retry; + } else { + read(fd, buf, 10); + if (strncmp(buf, "p >\r\n\r\n>", 8)) + goto nono; + } + } + return (1); +} diff --git a/usr.bin/tip/aculib/courier.c b/usr.bin/tip/aculib/courier.c new file mode 100644 index 0000000..85f7b0d --- /dev/null +++ b/usr.bin/tip/aculib/courier.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1986, 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[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for calling up on a Courier modem. + * Derived from Hayes driver. + */ +#include "tip.h" +#include + +#define MAXRETRY 5 + +static void sigALRM(); +static int timeout = 0; +static int connected = 0; +static jmp_buf timeoutbuf, intbuf; +static int coursync(); + +cour_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; +#ifdef ACULOG + char line[80]; +#endif + static int cour_connect(), cour_swallow(); + + if (boolean(value(VERBOSE))) + printf("Using \"%s\"\n", acu); + + ioctl(FD, TIOCHPCL, 0); + /* + * Get in synch. + */ + if (!coursync()) { +badsynch: + printf("can't synchronize with courier\n"); +#ifdef ACULOG + logent(value(HOST), num, "courier", "can't synch up"); +#endif + return (0); + } + cour_write(FD, "AT E0\r", 6); /* turn off echoing */ + sleep(1); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + cour_verbose_read(); +#endif + ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ + cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21); + if (!cour_swallow("\r\nOK\r\n")) + goto badsynch; + fflush(stdout); + cour_write(FD, "AT D", 4); + for (cp = num; *cp; cp++) + if (*cp == '=') + *cp = ','; + cour_write(FD, num, strlen(num)); + cour_write(FD, "\r", 1); + connected = cour_connect(); +#ifdef ACULOG + if (timeout) { + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "cour", line); + } +#endif + if (timeout) + cour_disconnect(); + return (connected); +} + +cour_disconnect() +{ + /* first hang up the modem*/ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + coursync(); /* reset */ + close(FD); +} + +cour_abort() +{ + cour_write(FD, "\r", 1); /* send anything to abort the call */ + cour_disconnect(); +} + +static void +sigALRM() +{ + printf("\07timeout waiting for reply\n"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +cour_swallow(match) + register char *match; + { + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + do { + if (*match =='\0') { + signal(SIGALRM, f); + return (1); + } + if (setjmp(timeoutbuf)) { + signal(SIGALRM, f); + return (0); + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + c &= 0177; +#ifdef DEBUG + if (boolean(value(VERBOSE))) + putchar(c); +#endif + } while (c == *match++); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + fflush(stdout); +#endif + signal(SIGALRM, SIG_DFL); + return (0); +} + +struct baud_msg { + char *msg; + int baud; +} baud_msg[] = { + "", B300, + " 1200", B1200, + " 2400", B2400, + " 9600", B9600, + " 9600/ARQ", B9600, + 0, 0, +}; + +static int +cour_connect() +{ + char c; + int nc, nl, n; + struct sgttyb sb; + char dialer_buf[64]; + struct baud_msg *bm; + sig_t f; + + if (cour_swallow("\r\n") == 0) + return (0); + f = signal(SIGALRM, sigALRM); +again: + nc = 0; nl = sizeof(dialer_buf)-1; + bzero(dialer_buf, sizeof(dialer_buf)); + timeout = 0; + for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { + if (setjmp(timeoutbuf)) + break; + alarm(number(value(DIALTIMEOUT))); + n = read(FD, &c, 1); + alarm(0); + if (n <= 0) + break; + c &= 0x7f; + if (c == '\r') { + if (cour_swallow("\n") == 0) + break; + if (!dialer_buf[0]) + goto again; + if (strcmp(dialer_buf, "RINGING") == 0 && + boolean(value(VERBOSE))) { +#ifdef DEBUG + printf("%s\r\n", dialer_buf); +#endif + goto again; + } + if (strncmp(dialer_buf, "CONNECT", + sizeof("CONNECT")-1) != 0) + break; + for (bm = baud_msg ; bm->msg ; bm++) + if (strcmp(bm->msg, + dialer_buf+sizeof("CONNECT")-1) == 0) { + if (ioctl(FD, TIOCGETP, &sb) < 0) { + perror("TIOCGETP"); + goto error; + } + sb.sg_ispeed = sb.sg_ospeed = bm->baud; + if (ioctl(FD, TIOCSETP, &sb) < 0) { + perror("TIOCSETP"); + goto error; + } + signal(SIGALRM, f); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + printf("%s\r\n", dialer_buf); +#endif + return (1); + } + break; + } + dialer_buf[nc] = c; +#ifdef notdef + if (boolean(value(VERBOSE))) + putchar(c); +#endif + } +error1: + printf("%s\r\n", dialer_buf); +error: + signal(SIGALRM, f); + return (0); +} + +/* + * This convoluted piece of code attempts to get + * the courier in sync. + */ +static int +coursync() +{ + int already = 0; + int len; + char buf[40]; + + while (already++ < MAXRETRY) { + ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ + cour_write(FD, "\rAT Z\r", 6); /* reset modem */ + bzero(buf, sizeof(buf)); + sleep(1); + ioctl(FD, FIONREAD, &len); + if (len) { + len = read(FD, buf, sizeof(buf)); +#ifdef DEBUG + buf[len] = '\0'; + printf("coursync: (\"%s\")\n\r", buf); +#endif + if (index(buf, '0') || + (index(buf, 'O') && index(buf, 'K'))) + return(1); + } + /* + * If not strapped for DTR control, + * try to get command mode. + */ + sleep(1); + cour_write(FD, "+++", 3); + sleep(1); + /* + * Toggle DTR to force anyone off that might have left + * the modem connected. + */ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + } + cour_write(FD, "\rAT Z\r", 6); + return (0); +} + +cour_write(fd, cp, n) +int fd; +char *cp; +int n; +{ + struct sgttyb sb; +#ifdef notdef + if (boolean(value(VERBOSE))) + write(1, cp, n); +#endif + ioctl(fd, TIOCGETP, &sb); + ioctl(fd, TIOCSETP, &sb); + cour_nap(); + for ( ; n-- ; cp++) { + write(fd, cp, 1); + ioctl(fd, TIOCGETP, &sb); + ioctl(fd, TIOCSETP, &sb); + cour_nap(); + } +} + +#ifdef DEBUG +cour_verbose_read() +{ + int n = 0; + char buf[BUFSIZ]; + + if (ioctl(FD, FIONREAD, &n) < 0) + return; + if (n <= 0) + return; + if (read(FD, buf, n) != n) + return; + write(1, buf, n); +} +#endif + +/* + * Code stolen from /usr/src/lib/libc/gen/sleep.c + */ +#define mask(s) (1<<((s)-1)) +#define setvec(vec, a) \ + vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 + +static napms = 50; /* Give the courier 50 milliseconds between characters */ + +static int ringring; + +cour_nap() +{ + + static void cour_napx(); + int omask; + struct itimerval itv, oitv; + register struct itimerval *itp = &itv; + struct sigvec vec, ovec; + + timerclear(&itp->it_interval); + timerclear(&itp->it_value); + if (setitimer(ITIMER_REAL, itp, &oitv) < 0) + return; + setvec(ovec, SIG_DFL); + omask = sigblock(mask(SIGALRM)); + itp->it_value.tv_sec = napms/1000; + itp->it_value.tv_usec = ((napms%1000)*1000); + setvec(vec, cour_napx); + ringring = 0; + (void) sigvec(SIGALRM, &vec, &ovec); + (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); + while (!ringring) + sigpause(omask &~ mask(SIGALRM)); + (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); + (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); + (void) sigsetmask(omask); +} + +static void +cour_napx() +{ + ringring = 1; +} diff --git a/usr.bin/tip/aculib/df.c b/usr.bin/tip/aculib/df.c new file mode 100644 index 0000000..5f294f9 --- /dev/null +++ b/usr.bin/tip/aculib/df.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)df.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Dial the DF02-AC or DF03-AC + */ + +#include "tip.h" + +static jmp_buf Sjbuf; +static void timeout(); + +df02_dialer(num, acu) + char *num, *acu; +{ + + return (df_dialer(num, acu, 0)); +} + +df03_dialer(num, acu) + char *num, *acu; +{ + + return (df_dialer(num, acu, 1)); +} + +df_dialer(num, acu, df03) + char *num, *acu; + int df03; +{ + register int f = FD; + struct sgttyb buf; + int speed = 0, rw = 2; + char c = '\0'; + + ioctl(f, TIOCHPCL, 0); /* make sure it hangs up when done */ + if (setjmp(Sjbuf)) { + printf("connection timed out\r\n"); + df_disconnect(); + return (0); + } + if (boolean(value(VERBOSE))) + printf("\ndialing..."); + fflush(stdout); +#ifdef TIOCMSET + if (df03) { + int st = TIOCM_ST; /* secondary Transmit flag */ + + ioctl(f, TIOCGETP, &buf); + if (buf.sg_ospeed != B1200) { /* must dial at 1200 baud */ + speed = buf.sg_ospeed; + buf.sg_ospeed = buf.sg_ispeed = B1200; + ioctl(f, TIOCSETP, &buf); + ioctl(f, TIOCMBIC, &st); /* clear ST for 300 baud */ + } else + ioctl(f, TIOCMBIS, &st); /* set ST for 1200 baud */ + } +#endif + signal(SIGALRM, timeout); + alarm(5 * strlen(num) + 10); + ioctl(f, TIOCFLUSH, &rw); + write(f, "\001", 1); + sleep(1); + write(f, "\002", 1); + write(f, num, strlen(num)); + read(f, &c, 1); +#ifdef TIOCMSET + if (df03 && speed) { + buf.sg_ispeed = buf.sg_ospeed = speed; + ioctl(f, TIOCSETP, &buf); + } +#endif + return (c == 'A'); +} + +df_disconnect() +{ + int rw = 2; + + write(FD, "\001", 1); + sleep(1); + ioctl(FD, TIOCFLUSH, &rw); +} + + +df_abort() +{ + + df_disconnect(); +} + + +static void +timeout() +{ + + longjmp(Sjbuf, 1); +} diff --git a/usr.bin/tip/aculib/dn11.c b/usr.bin/tip/aculib/dn11.c new file mode 100644 index 0000000..152b376 --- /dev/null +++ b/usr.bin/tip/aculib/dn11.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)dn11.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for dialing up on DN-11 + */ +#include "tip.h" + +int dn_abort(); +void alarmtr(); +static jmp_buf jmpbuf; +static int child = -1, dn; + +dn_dialer(num, acu) + char *num, *acu; +{ + extern errno; + char *p, *q, phone[40]; + int lt, nw, connected = 1; + register int timelim; + + if (boolean(value(VERBOSE))) + printf("\nstarting call..."); + if ((dn = open(acu, 1)) < 0) { + if (errno == EBUSY) + printf("line busy..."); + else + printf("acu open error..."); + return (0); + } + if (setjmp(jmpbuf)) { + kill(child, SIGKILL); + close(dn); + return (0); + } + signal(SIGALRM, alarmtr); + timelim = 5 * strlen(num); + alarm(timelim < 30 ? 30 : timelim); + if ((child = fork()) == 0) { + /* + * ignore this stuff for aborts + */ + signal(SIGALRM, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + sleep(2); + nw = write(dn, num, lt = strlen(num)); + exit(nw != lt); + } + /* + * open line - will return on carrier + */ + if ((FD = open(DV, 2)) < 0) { + if (errno == EIO) + printf("lost carrier..."); + else + printf("dialup line open failed..."); + alarm(0); + kill(child, SIGKILL); + close(dn); + return (0); + } + alarm(0); + ioctl(dn, TIOCHPCL, 0); + signal(SIGALRM, SIG_DFL); + while ((nw = wait(<)) != child && nw != -1) + ; + fflush(stdout); + close(dn); + if (lt != 0) { + close(FD); + return (0); + } + return (1); +} + +void +alarmtr() +{ + alarm(0); + longjmp(jmpbuf, 1); +} + +/* + * Insurance, for some reason we don't seem to be + * hanging up... + */ +dn_disconnect() +{ + + sleep(2); + if (FD > 0) + ioctl(FD, TIOCCDTR, 0); + close(FD); +} + +dn_abort() +{ + + sleep(2); + if (child > 0) + kill(child, SIGKILL); + if (dn > 0) + close(dn); + if (FD > 0) + ioctl(FD, TIOCCDTR, 0); + close(FD); +} diff --git a/usr.bin/tip/aculib/hayes.c b/usr.bin/tip/aculib/hayes.c new file mode 100644 index 0000000..a2196f4 --- /dev/null +++ b/usr.bin/tip/aculib/hayes.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for calling up on a Hayes Modem + * (based on the old VenTel driver). + * The modem is expected to be strapped for "echo". + * Also, the switches enabling the DTR and CD lines + * must be set correctly. + * NOTICE: + * The easy way to hang up a modem is always simply to + * clear the DTR signal. However, if the +++ sequence + * (which switches the modem back to local mode) is sent + * before modem is hung up, removal of the DTR signal + * has no effect (except that it prevents the modem from + * recognizing commands). + * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984) + */ +/* + * TODO: + * It is probably not a good idea to switch the modem + * state between 'verbose' and terse (status messages). + * This should be kicked out and we should use verbose + * mode only. This would make it consistent with normal + * interactive use thru the command 'tip dialer'. + */ +#include "tip.h" + +#define min(a,b) ((a < b) ? a : b) + +static void sigALRM(); +static int timeout = 0; +static jmp_buf timeoutbuf; +static char gobble(); +#define DUMBUFLEN 40 +static char dumbuf[DUMBUFLEN]; + +#define DIALING 1 +#define IDLE 2 +#define CONNECTED 3 +#define FAILED 4 +static int state = IDLE; + +hay_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; + register int connected = 0; + char dummy; +#ifdef ACULOG + char line[80]; +#endif + if (hay_sync() == 0) /* make sure we can talk to the modem */ + return(0); + if (boolean(value(VERBOSE))) + printf("\ndialing..."); + fflush(stdout); + ioctl(FD, TIOCHPCL, 0); + ioctl(FD, TIOCFLUSH, 0); /* get rid of garbage */ + write(FD, "ATv0\r", 5); /* tell modem to use short status codes */ + gobble("\r"); + gobble("\r"); + write(FD, "ATTD", 4); /* send dial command */ + write(FD, num, strlen(num)); + state = DIALING; + write(FD, "\r", 1); + connected = 0; + if (gobble("\r")) { + if ((dummy = gobble("01234")) != '1') + error_rep(dummy); + else + connected = 1; + } + if (connected) + state = CONNECTED; + else { + state = FAILED; + return (connected); /* lets get out of here.. */ + } + ioctl(FD, TIOCFLUSH, 0); +#ifdef ACULOG + if (timeout) { + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "hayes", line); + } +#endif + if (timeout) + hay_disconnect(); /* insurance */ + return (connected); +} + + +hay_disconnect() +{ + char c; + int len, rlen; + + /* first hang up the modem*/ +#ifdef DEBUG + printf("\rdisconnecting modem....\n\r"); +#endif + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + goodbye(); +} + +hay_abort() +{ + + char c; + + write(FD, "\r", 1); /* send anything to abort the call */ + hay_disconnect(); +} + +static void +sigALRM() +{ + + printf("\07timeout waiting for reply\n\r"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static char +gobble(match) + register char *match; +{ + char c; + sig_t f; + int i, status = 0; + + f = signal(SIGALRM, sigALRM); + timeout = 0; +#ifdef DEBUG + printf("\ngobble: waiting for %s\n", match); +#endif + do { + if (setjmp(timeoutbuf)) { + signal(SIGALRM, f); + return (0); + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + c &= 0177; +#ifdef DEBUG + printf("%c 0x%x ", c, c); +#endif + for (i = 0; i < strlen(match); i++) + if (c == match[i]) + status = c; + } while (status == 0); + signal(SIGALRM, SIG_DFL); +#ifdef DEBUG + printf("\n"); +#endif + return (status); +} + +error_rep(c) + register char c; +{ + printf("\n\r"); + switch (c) { + + case '0': + printf("OK"); + break; + + case '1': + printf("CONNECT"); + break; + + case '2': + printf("RING"); + break; + + case '3': + printf("NO CARRIER"); + break; + + case '4': + printf("ERROR in input"); + break; + + case '5': + printf("CONNECT 1200"); + break; + + default: + printf("Unknown Modem error: %c (0x%x)", c, c); + } + printf("\n\r"); + return; +} + +/* + * set modem back to normal verbose status codes. + */ +goodbye() +{ + int len, rlen; + char c; + + ioctl(FD, TIOCFLUSH, &len); /* get rid of trash */ + if (hay_sync()) { + sleep(1); +#ifndef DEBUG + ioctl(FD, TIOCFLUSH, 0); +#endif + write(FD, "ATH0\r", 5); /* insurance */ +#ifndef DEBUG + c = gobble("03"); + if (c != '0' && c != '3') { + printf("cannot hang up modem\n\r"); + printf("please use 'tip dialer' to make sure the line is hung up\n\r"); + } +#endif + sleep(1); + ioctl(FD, FIONREAD, &len); +#ifdef DEBUG + printf("goodbye1: len=%d -- ", len); + rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); + dumbuf[rlen] = '\0'; + printf("read (%d): %s\r\n", rlen, dumbuf); +#endif + write(FD, "ATv1\r", 5); + sleep(1); +#ifdef DEBUG + ioctl(FD, FIONREAD, &len); + printf("goodbye2: len=%d -- ", len); + rlen = read(FD, dumbuf, min(len, DUMBUFLEN)); + dumbuf[rlen] = '\0'; + printf("read (%d): %s\r\n", rlen, dumbuf); +#endif + } + ioctl(FD, TIOCFLUSH, 0); /* clear the input buffer */ + ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */ + close(FD); +} + +#define MAXRETRY 5 + +hay_sync() +{ + int len, retry = 0; + + while (retry++ <= MAXRETRY) { + write(FD, "AT\r", 3); + sleep(1); + ioctl(FD, FIONREAD, &len); + if (len) { + len = read(FD, dumbuf, min(len, DUMBUFLEN)); + if (index(dumbuf, '0') || + (index(dumbuf, 'O') && index(dumbuf, 'K'))) + return(1); +#ifdef DEBUG + dumbuf[len] = '\0'; + printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry); +#endif + } + ioctl(FD, TIOCCDTR, 0); + ioctl(FD, TIOCSDTR, 0); + } + printf("Cannot synchronize with hayes...\n\r"); + return(0); +} diff --git a/usr.bin/tip/aculib/t3000.c b/usr.bin/tip/aculib/t3000.c new file mode 100644 index 0000000..5e07359 --- /dev/null +++ b/usr.bin/tip/aculib/t3000.c @@ -0,0 +1,408 @@ +/* + * 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[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for calling up on a Telebit T3000 modem. + * Derived from Courier driver. + */ +#include "tip.h" +#include + +#define MAXRETRY 5 + +static void sigALRM(); +static int timeout = 0; +static int connected = 0; +static jmp_buf timeoutbuf, intbuf; +static int t3000_sync(); + +t3000_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; +#ifdef ACULOG + char line[80]; +#endif + static int t3000_connect(), t3000_swallow(); + + if (boolean(value(VERBOSE))) + printf("Using \"%s\"\n", acu); + + ioctl(FD, TIOCHPCL, 0); + /* + * Get in synch. + */ + if (!t3000_sync()) { +badsynch: + printf("can't synchronize with t3000\n"); +#ifdef ACULOG + logent(value(HOST), num, "t3000", "can't synch up"); +#endif + return (0); + } + t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ + sleep(1); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + t3000_verbose_read(); +#endif + ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ + t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); + if (!t3000_swallow("\r\nOK\r\n")) + goto badsynch; + fflush(stdout); + t3000_write(FD, "AT D", 4); + for (cp = num; *cp; cp++) + if (*cp == '=') + *cp = ','; + t3000_write(FD, num, strlen(num)); + t3000_write(FD, "\r", 1); + connected = t3000_connect(); +#ifdef ACULOG + if (timeout) { + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "t3000", line); + } +#endif + if (timeout) + t3000_disconnect(); + return (connected); +} + +t3000_disconnect() +{ + /* first hang up the modem*/ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + t3000_sync(); /* reset */ + close(FD); +} + +t3000_abort() +{ + t3000_write(FD, "\r", 1); /* send anything to abort the call */ + t3000_disconnect(); +} + +static void +sigALRM() +{ + printf("\07timeout waiting for reply\n"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +t3000_swallow(match) + register char *match; + { + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + do { + if (*match =='\0') { + signal(SIGALRM, f); + return (1); + } + if (setjmp(timeoutbuf)) { + signal(SIGALRM, f); + return (0); + } + alarm(number(value(DIALTIMEOUT))); + read(FD, &c, 1); + alarm(0); + c &= 0177; +#ifdef DEBUG + if (boolean(value(VERBOSE))) + putchar(c); +#endif + } while (c == *match++); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + fflush(stdout); +#endif + signal(SIGALRM, SIG_DFL); + return (0); +} + +#ifndef B19200 /* XXX */ +#define B19200 EXTA +#define B38400 EXTB +#endif + +struct tbaud_msg { + char *msg; + int baud; + int baud2; +} tbaud_msg[] = { + "", B300, 0, + " 1200", B1200, 0, + " 2400", B2400, 0, + " 4800", B4800, 0, + " 9600", B9600, 0, + " 14400", B19200, B9600, + " 19200", B19200, B9600, + " 38400", B38400, B9600, + " 57600", B38400, B9600, + " 7512", B9600, 0, + " 1275", B2400, 0, + " 7200", B9600, 0, + " 12000", B19200, B9600, + 0, 0, 0, +}; + +static int +t3000_connect() +{ + char c; + int nc, nl, n; + struct sgttyb sb; + char dialer_buf[64]; + struct tbaud_msg *bm; + sig_t f; + + if (t3000_swallow("\r\n") == 0) + return (0); + f = signal(SIGALRM, sigALRM); +again: + nc = 0; nl = sizeof(dialer_buf)-1; + bzero(dialer_buf, sizeof(dialer_buf)); + timeout = 0; + for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { + if (setjmp(timeoutbuf)) + break; + alarm(number(value(DIALTIMEOUT))); + n = read(FD, &c, 1); + alarm(0); + if (n <= 0) + break; + c &= 0x7f; + if (c == '\r') { + if (t3000_swallow("\n") == 0) + break; + if (!dialer_buf[0]) + goto again; + if (strcmp(dialer_buf, "RINGING") == 0 && + boolean(value(VERBOSE))) { +#ifdef DEBUG + printf("%s\r\n", dialer_buf); +#endif + goto again; + } + if (strncmp(dialer_buf, "CONNECT", + sizeof("CONNECT")-1) != 0) + break; + for (bm = tbaud_msg ; bm->msg ; bm++) + if (strcmp(bm->msg, + dialer_buf+sizeof("CONNECT")-1) == 0) { + if (ioctl(FD, TIOCGETP, &sb) < 0) { + perror("TIOCGETP"); + goto error; + } + sb.sg_ispeed = sb.sg_ospeed = bm->baud; + if (ioctl(FD, TIOCSETP, &sb) < 0) { + if (bm->baud2) { + sb.sg_ispeed = + sb.sg_ospeed = + bm->baud2; + if (ioctl(FD, + TIOCSETP, + &sb) >= 0) + goto isok; + } + perror("TIOCSETP"); + goto error; + } +isok: + signal(SIGALRM, f); +#ifdef DEBUG + if (boolean(value(VERBOSE))) + printf("%s\r\n", dialer_buf); +#endif + return (1); + } + break; + } + dialer_buf[nc] = c; +#ifdef notdef + if (boolean(value(VERBOSE))) + putchar(c); +#endif + } +error1: + printf("%s\r\n", dialer_buf); +error: + signal(SIGALRM, f); + return (0); +} + +/* + * This convoluted piece of code attempts to get + * the t3000 in sync. + */ +static int +t3000_sync() +{ + int already = 0; + int len; + char buf[40]; + + while (already++ < MAXRETRY) { + ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ + t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ + bzero(buf, sizeof(buf)); + sleep(2); + ioctl(FD, FIONREAD, &len); +#if 1 +if (len == 0) len = 1; +#endif + if (len) { + len = read(FD, buf, sizeof(buf)); +#ifdef DEBUG + buf[len] = '\0'; + printf("t3000_sync: (\"%s\")\n\r", buf); +#endif + if (index(buf, '0') || + (index(buf, 'O') && index(buf, 'K'))) + return(1); + } + /* + * If not strapped for DTR control, + * try to get command mode. + */ + sleep(1); + t3000_write(FD, "+++", 3); + sleep(1); + /* + * Toggle DTR to force anyone off that might have left + * the modem connected. + */ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + } + t3000_write(FD, "\rAT Z\r", 6); + return (0); +} + +t3000_write(fd, cp, n) +int fd; +char *cp; +int n; +{ + struct sgttyb sb; + +#ifdef notdef + if (boolean(value(VERBOSE))) + write(1, cp, n); +#endif + ioctl(fd, TIOCGETP, &sb); + ioctl(fd, TIOCSETP, &sb); + t3000_nap(); + for ( ; n-- ; cp++) { + write(fd, cp, 1); + ioctl(fd, TIOCGETP, &sb); + ioctl(fd, TIOCSETP, &sb); + t3000_nap(); + } +} + +#ifdef DEBUG +t3000_verbose_read() +{ + int n = 0; + char buf[BUFSIZ]; + + if (ioctl(FD, FIONREAD, &n) < 0) + return; + if (n <= 0) + return; + if (read(FD, buf, n) != n) + return; + write(1, buf, n); +} +#endif + +/* + * Code stolen from /usr/src/lib/libc/gen/sleep.c + */ +#define mask(s) (1<<((s)-1)) +#define setvec(vec, a) \ + vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 + +static napms = 50; /* Give the t3000 50 milliseconds between characters */ + +static int ringring; + +t3000_nap() +{ + + static void t3000_napx(); + int omask; + struct itimerval itv, oitv; + register struct itimerval *itp = &itv; + struct sigvec vec, ovec; + + timerclear(&itp->it_interval); + timerclear(&itp->it_value); + if (setitimer(ITIMER_REAL, itp, &oitv) < 0) + return; + setvec(ovec, SIG_DFL); + omask = sigblock(mask(SIGALRM)); + itp->it_value.tv_sec = napms/1000; + itp->it_value.tv_usec = ((napms%1000)*1000); + setvec(vec, t3000_napx); + ringring = 0; + (void) sigvec(SIGALRM, &vec, &ovec); + (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); + while (!ringring) + sigpause(omask &~ mask(SIGALRM)); + (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); + (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); + (void) sigsetmask(omask); +} + +static void +t3000_napx() +{ + ringring = 1; +} diff --git a/usr.bin/tip/aculib/v3451.c b/usr.bin/tip/aculib/v3451.c new file mode 100644 index 0000000..1623a58 --- /dev/null +++ b/usr.bin/tip/aculib/v3451.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)v3451.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for calling up on a Vadic 3451 Modem + */ +#include "tip.h" + +static jmp_buf Sjbuf; + +v3451_dialer(num, acu) + register char *num; + char *acu; +{ + sig_t func; + int ok; + int slow = number(value(BAUDRATE)) < 1200, rw = 2; + char phone[50]; +#ifdef ACULOG + char line[80]; +#endif + static int expect(); + static void vawrite(); + + /* + * Get in synch + */ + vawrite("I\r", 1 + slow); + vawrite("I\r", 1 + slow); + vawrite("I\r", 1 + slow); + vawrite("\005\r", 2 + slow); + if (!expect("READY")) { + printf("can't synchronize with vadic 3451\n"); +#ifdef ACULOG + logent(value(HOST), num, "vadic", "can't synch up"); +#endif + return (0); + } + ioctl(FD, TIOCHPCL, 0); + sleep(1); + vawrite("D\r", 2 + slow); + if (!expect("NUMBER?")) { + printf("Vadic will not accept dial command\n"); +#ifdef ACULOG + logent(value(HOST), num, "vadic", "will not accept dial"); +#endif + return (0); + } + strcpy(phone, num); + strcat(phone, "\r"); + vawrite(phone, 1 + slow); + if (!expect(phone)) { + printf("Vadic will not accept phone number\n"); +#ifdef ACULOG + logent(value(HOST), num, "vadic", "will not accept number"); +#endif + return (0); + } + func = signal(SIGINT,SIG_IGN); + /* + * You cannot interrupt the Vadic when its dialing; + * even dropping DTR does not work (definitely a + * brain damaged design). + */ + vawrite("\r", 1 + slow); + vawrite("\r", 1 + slow); + if (!expect("DIALING:")) { + printf("Vadic failed to dial\n"); +#ifdef ACULOG + logent(value(HOST), num, "vadic", "failed to dial"); +#endif + return (0); + } + if (boolean(value(VERBOSE))) + printf("\ndialing..."); + ok = expect("ON LINE"); + signal(SIGINT, func); + if (!ok) { + printf("call failed\n"); +#ifdef ACULOG + logent(value(HOST), num, "vadic", "call failed"); +#endif + return (0); + } + ioctl(FD, TIOCFLUSH, &rw); + return (1); +} + +v3451_disconnect() +{ + + close(FD); +} + +v3451_abort() +{ + + close(FD); +} + +static void +vawrite(cp, delay) + register char *cp; + int delay; +{ + + for (; *cp; sleep(delay), cp++) + write(FD, cp, 1); +} + +static +expect(cp) + register char *cp; +{ + char buf[300]; + register char *rp = buf; + int timeout = 30, online = 0; + static int notin(); + static void alarmtr(); + + if (strcmp(cp, "\"\"") == 0) + return (1); + *rp = 0; + /* + * If we are waiting for the Vadic to complete + * dialing and get a connection, allow more time + * Unfortunately, the Vadic times out 24 seconds after + * the last digit is dialed + */ + online = strcmp(cp, "ON LINE") == 0; + if (online) + timeout = number(value(DIALTIMEOUT)); + signal(SIGALRM, alarmtr); + if (setjmp(Sjbuf)) + return (0); + alarm(timeout); + while (notin(cp, buf) && rp < buf + sizeof (buf) - 1) { + if (online && notin("FAILED CALL", buf) == 0) + return (0); + if (read(FD, rp, 1) < 0) { + alarm(0); + return (0); + } + if (*rp &= 0177) + rp++; + *rp = '\0'; + } + alarm(0); + return (1); +} + +static void +alarmtr() +{ + longjmp(Sjbuf, 1); +} + +static int +notin(sh, lg) + char *sh, *lg; +{ + static int prefix(); + + for (; *lg; lg++) + if (prefix(sh, lg)) + return (0); + return (1); +} + +static +prefix(s1, s2) + register char *s1, *s2; +{ + register char c; + + while ((c = *s1++) == *s2++) + if (c == '\0') + return (1); + return (c == '\0'); +} diff --git a/usr.bin/tip/aculib/v831.c b/usr.bin/tip/aculib/v831.c new file mode 100644 index 0000000..38aa230 --- /dev/null +++ b/usr.bin/tip/aculib/v831.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)v831.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for dialing up on Vadic 831 + */ +#include "tip.h" + +int v831_abort(); +static void alarmtr(); +extern int errno; + +static jmp_buf jmpbuf; +static int child = -1; + +v831_dialer(num, acu) + char *num, *acu; +{ + int status, pid, connected = 1; + register int timelim; + static int dialit(); + + if (boolean(value(VERBOSE))) + printf("\nstarting call..."); +#ifdef DEBUG + printf ("(acu=%s)\n", acu); +#endif + if ((AC = open(acu, O_RDWR)) < 0) { + if (errno == EBUSY) + printf("line busy..."); + else + printf("acu open error..."); + return (0); + } + if (setjmp(jmpbuf)) { + kill(child, SIGKILL); + close(AC); + return (0); + } + signal(SIGALRM, alarmtr); + timelim = 5 * strlen(num); + alarm(timelim < 30 ? 30 : timelim); + if ((child = fork()) == 0) { + /* + * ignore this stuff for aborts + */ + signal(SIGALRM, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + sleep(2); + exit(dialit(num, acu) != 'A'); + } + /* + * open line - will return on carrier + */ + if ((FD = open(DV, O_RDWR)) < 0) { +#ifdef DEBUG + printf("(after open, errno=%d)\n", errno); +#endif + if (errno == EIO) + printf("lost carrier..."); + else + printf("dialup line open failed..."); + alarm(0); + kill(child, SIGKILL); + close(AC); + return (0); + } + alarm(0); +#ifdef notdef + ioctl(AC, TIOCHPCL, 0); +#endif + signal(SIGALRM, SIG_DFL); + while ((pid = wait(&status)) != child && pid != -1) + ; + if (status) { + close(AC); + return (0); + } + return (1); +} + +static void +alarmtr() +{ + alarm(0); + longjmp(jmpbuf, 1); +} + +/* + * Insurance, for some reason we don't seem to be + * hanging up... + */ +v831_disconnect() +{ + struct sgttyb cntrl; + + sleep(2); +#ifdef DEBUG + printf("[disconnect: FD=%d]\n", FD); +#endif + if (FD > 0) { + ioctl(FD, TIOCCDTR, 0); + ioctl(FD, TIOCGETP, &cntrl); + cntrl.sg_ispeed = cntrl.sg_ospeed = 0; + ioctl(FD, TIOCSETP, &cntrl); + ioctl(FD, TIOCNXCL, (struct sgttyb *)NULL); + } + close(FD); +} + +v831_abort() +{ + +#ifdef DEBUG + printf("[abort: AC=%d]\n", AC); +#endif + sleep(2); + if (child > 0) + kill(child, SIGKILL); + if (AC > 0) + ioctl(FD, TIOCNXCL, (struct sgttyb *)NULL); + close(AC); + if (FD > 0) + ioctl(FD, TIOCCDTR, 0); + close(FD); +} + +/* + * Sigh, this probably must be changed at each site. + */ +struct vaconfig { + char *vc_name; + char vc_rack; + char vc_modem; +} vaconfig[] = { + { "/dev/cua0",'4','0' }, + { "/dev/cua1",'4','1' }, + { 0 } +}; + +#define pc(x) (c = x, write(AC,&c,1)) +#define ABORT 01 +#define SI 017 +#define STX 02 +#define ETX 03 + +static int +dialit(phonenum, acu) + register char *phonenum; + char *acu; +{ + register struct vaconfig *vp; + struct sgttyb cntrl; + char c; + int i, two = 2; + static char *sanitize(); + + phonenum = sanitize(phonenum); +#ifdef DEBUG + printf ("(dial phonenum=%s)\n", phonenum); +#endif + if (*phonenum == '<' && phonenum[1] == 0) + return ('Z'); + for (vp = vaconfig; vp->vc_name; vp++) + if (strcmp(vp->vc_name, acu) == 0) + break; + if (vp->vc_name == 0) { + printf("Unable to locate dialer (%s)\n", acu); + return ('K'); + } + ioctl(AC, TIOCGETP, &cntrl); + cntrl.sg_ispeed = cntrl.sg_ospeed = B2400; + cntrl.sg_flags = RAW | EVENP | ODDP; + ioctl(AC, TIOCSETP, &cntrl); + ioctl(AC, TIOCFLUSH, &two); + pc(STX); + pc(vp->vc_rack); + pc(vp->vc_modem); + while (*phonenum && *phonenum != '<') + pc(*phonenum++); + pc(SI); + pc(ETX); + sleep(1); + i = read(AC, &c, 1); +#ifdef DEBUG + printf("read %d chars, char=%c, errno %d\n", i, c, errno); +#endif + if (i != 1) + c = 'M'; + if (c == 'B' || c == 'G') { + char cc, oc = c; + + pc(ABORT); + read(AC, &cc, 1); +#ifdef DEBUG + printf("abort response=%c\n", cc); +#endif + c = oc; + v831_disconnect(); + } + close(AC); +#ifdef DEBUG + printf("dialit: returns %c\n", c); +#endif + return (c); +} + +static char * +sanitize(s) + register char *s; +{ + static char buf[128]; + register char *cp; + + for (cp = buf; *s; s++) { + if (!isdigit(*s) && *s == '<' && *s != '_') + continue; + if (*s == '_') + *s = '='; + *cp++ = *s; + } + *cp++ = 0; + return (buf); +} diff --git a/usr.bin/tip/aculib/ventel.c b/usr.bin/tip/aculib/ventel.c new file mode 100644 index 0000000..28b0d28 --- /dev/null +++ b/usr.bin/tip/aculib/ventel.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)ventel.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines for calling up on a Ventel Modem + * The Ventel is expected to be strapped for local echo (just like uucp) + */ +#include "tip.h" + +#define MAXRETRY 5 + +static void sigALRM(); +static int timeout = 0; +static jmp_buf timeoutbuf; + +/* + * some sleep calls have been replaced by this macro + * because some ventel modems require two s in less than + * a second in order to 'wake up'... yes, it is dirty... + */ +#define delay(num,denom) busyloop(CPUSPEED*num/denom) +#define CPUSPEED 1000000 /* VAX 780 is 1MIPS */ +#define DELAY(n) { register long N = (n); while (--N > 0); } +busyloop(n) { DELAY(n); } + +ven_dialer(num, acu) + register char *num; + char *acu; +{ + register char *cp; + register int connected = 0; + char *msg, *index(), line[80]; + static int gobble(), vensync(); + static void echo(); + + /* + * Get in synch with a couple of carriage returns + */ + if (!vensync(FD)) { + printf("can't synchronize with ventel\n"); +#ifdef ACULOG + logent(value(HOST), num, "ventel", "can't synch up"); +#endif + return (0); + } + if (boolean(value(VERBOSE))) + printf("\ndialing..."); + fflush(stdout); + ioctl(FD, TIOCHPCL, 0); + echo("#k$\r$\n$D$I$A$L$:$ "); + for (cp = num; *cp; cp++) { + delay(1, 10); + write(FD, cp, 1); + } + delay(1, 10); + write(FD, "\r", 1); + gobble('\n', line); + if (gobble('\n', line)) + connected = gobble('!', line); + ioctl(FD, TIOCFLUSH); +#ifdef ACULOG + if (timeout) { + sprintf(line, "%d second dial timeout", + number(value(DIALTIMEOUT))); + logent(value(HOST), num, "ventel", line); + } +#endif + if (timeout) + ven_disconnect(); /* insurance */ + if (connected || timeout || !boolean(value(VERBOSE))) + return (connected); + /* call failed, parse response for user */ + cp = index(line, '\r'); + if (cp) + *cp = '\0'; + for (cp = line; cp = index(cp, ' '); cp++) + if (cp[1] == ' ') + break; + if (cp) { + while (*cp == ' ') + cp++; + msg = cp; + while (*cp) { + if (isupper(*cp)) + *cp = tolower(*cp); + cp++; + } + printf("%s...", msg); + } + return (connected); +} + +ven_disconnect() +{ + + close(FD); +} + +ven_abort() +{ + + write(FD, "\03", 1); + close(FD); +} + +static void +echo(s) + register char *s; +{ + char c; + + while (c = *s++) switch (c) { + + case '$': + read(FD, &c, 1); + s++; + break; + + case '#': + c = *s++; + write(FD, &c, 1); + break; + + default: + write(FD, &c, 1); + read(FD, &c, 1); + } +} + +static void +sigALRM() +{ + printf("\07timeout waiting for reply\n"); + timeout = 1; + longjmp(timeoutbuf, 1); +} + +static int +gobble(match, response) + register char match; + char response[]; +{ + register char *cp = response; + sig_t f; + char c; + + f = signal(SIGALRM, sigALRM); + timeout = 0; + do { + if (setjmp(timeoutbuf)) { + signal(SIGALRM, f); + *cp = '\0'; + return (0); + } + alarm(number(value(DIALTIMEOUT))); + read(FD, cp, 1); + alarm(0); + c = (*cp++ &= 0177); +#ifdef notdef + if (boolean(value(VERBOSE))) + putchar(c); +#endif + } while (c != '\n' && c != match); + signal(SIGALRM, SIG_DFL); + *cp = '\0'; + return (c == match); +} + +#define min(a,b) ((a)>(b)?(b):(a)) +/* + * This convoluted piece of code attempts to get + * the ventel in sync. If you don't have FIONREAD + * there are gory ways to simulate this. + */ +static int +vensync(fd) +{ + int already = 0, nread; + char buf[60]; + + /* + * Toggle DTR to force anyone off that might have left + * the modem connected, and insure a consistent state + * to start from. + * + * If you don't have the ioctl calls to diddle directly + * with DTR, you can always try setting the baud rate to 0. + */ + ioctl(FD, TIOCCDTR, 0); + sleep(1); + ioctl(FD, TIOCSDTR, 0); + while (already < MAXRETRY) { + /* + * After reseting the modem, send it two \r's to + * autobaud on. Make sure to delay between them + * so the modem can frame the incoming characters. + */ + write(fd, "\r", 1); + delay(1,10); + write(fd, "\r", 1); + sleep(2); + if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) { + perror("tip: ioctl"); + continue; + } + while (nread > 0) { + read(fd, buf, min(nread, 60)); + if ((buf[nread - 1] & 0177) == '$') + return (1); + nread -= min(nread, 60); + } + sleep(1); + already++; + } + return (0); +} + diff --git a/usr.bin/tip/acutab.c b/usr.bin/tip/acutab.c new file mode 100644 index 0000000..112b43e --- /dev/null +++ b/usr.bin/tip/acutab.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)acutab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +extern int df02_dialer(), df03_dialer(), df_disconnect(), df_abort(), + biz31f_dialer(), biz31_disconnect(), biz31_abort(), + biz31w_dialer(), + biz22f_dialer(), biz22_disconnect(), biz22_abort(), + biz22w_dialer(), + ven_dialer(), ven_disconnect(), ven_abort(), + hay_dialer(), hay_disconnect(), hay_abort(), + cour_dialer(), cour_disconnect(), cour_abort(), + t3000_dialer(), t3000_disconnect(), t3000_abort(), + v3451_dialer(), v3451_disconnect(), v3451_abort(), + v831_dialer(), v831_disconnect(), v831_abort(), + dn_dialer(), dn_disconnect(), dn_abort(); + +acu_t acutable[] = { +#if BIZ1031 + "biz31f", biz31f_dialer, biz31_disconnect, biz31_abort, + "biz31w", biz31w_dialer, biz31_disconnect, biz31_abort, +#endif +#if BIZ1022 + "biz22f", biz22f_dialer, biz22_disconnect, biz22_abort, + "biz22w", biz22w_dialer, biz22_disconnect, biz22_abort, +#endif +#if DF02 + "df02", df02_dialer, df_disconnect, df_abort, +#endif +#if DF03 + "df03", df03_dialer, df_disconnect, df_abort, +#endif +#if DN11 + "dn11", dn_dialer, dn_disconnect, dn_abort, +#endif +#ifdef VENTEL + "ventel",ven_dialer, ven_disconnect, ven_abort, +#endif +#ifdef HAYES + "hayes",hay_dialer, hay_disconnect, hay_abort, +#endif +#ifdef COURIER + "courier",cour_dialer, cour_disconnect, cour_abort, +#endif +#ifdef T3000 + "t3000",t3000_dialer, t3000_disconnect, t3000_abort, +#endif +#ifdef V3451 +#ifndef V831 + "vadic",v3451_dialer, v3451_disconnect, v3451_abort, +#endif + "v3451",v3451_dialer, v3451_disconnect, v3451_abort, +#endif +#ifdef V831 +#ifndef V3451 + "vadic",v831_dialer, v831_disconnect, v831_abort, +#endif + "v831",v831_dialer, v831_disconnect, v831_abort, +#endif + 0, 0, 0, 0 +}; + diff --git a/usr.bin/tip/cmds.c b/usr.bin/tip/cmds.c new file mode 100644 index 0000000..63bfee2 --- /dev/null +++ b/usr.bin/tip/cmds.c @@ -0,0 +1,888 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" +#include "pathnames.h" + +/* + * tip + * + * miscellaneous commands + */ + +int quant[] = { 60, 60, 24 }; + +char null = '\0'; +char *sep[] = { "second", "minute", "hour" }; +static char *argv[10]; /* argument vector for take and put */ + +void timeout(); /* timeout function called on alarm */ +void stopsnd(); /* SIGINT handler during file transfers */ +void intcopy(); /* interrupt routine for file transfers */ + +/* + * FTP - remote ==> local + * get a file from the remote host + */ +getfl(c) + char c; +{ + char buf[256], *cp, *expand(); + + putchar(c); + /* + * get the UNIX receiving file's name + */ + if (prompt("Local file name? ", copyname)) + return; + cp = expand(copyname); + if ((sfd = creat(cp, 0666)) < 0) { + printf("\r\n%s: cannot creat\r\n", copyname); + return; + } + + /* + * collect parameters + */ + if (prompt("List command for remote system? ", buf)) { + unlink(copyname); + return; + } + transfer(buf, sfd, value(EOFREAD)); +} + +/* + * Cu-like take command + */ +cu_take(cc) + char cc; +{ + int fd, argc; + char line[BUFSIZ], *expand(), *cp; + + if (prompt("[take] ", copyname)) + return; + if ((argc = args(copyname, argv)) < 1 || argc > 2) { + printf("usage: from [to]\r\n"); + return; + } + if (argc == 1) + argv[1] = argv[0]; + cp = expand(argv[1]); + if ((fd = creat(cp, 0666)) < 0) { + printf("\r\n%s: cannot create\r\n", argv[1]); + return; + } + sprintf(line, "cat %s;echo \01", argv[0]); + transfer(line, fd, "\01"); +} + +static jmp_buf intbuf; +/* + * Bulk transfer routine -- + * used by getfl(), cu_take(), and pipefile() + */ +transfer(buf, fd, eofchars) + char *buf, *eofchars; +{ + register int ct; + char c, buffer[BUFSIZ]; + register char *p = buffer; + register int cnt, eof; + time_t start; + sig_t f; + char r; + + pwrite(FD, buf, size(buf)); + quit = 0; + kill(pid, SIGIOT); + read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ + + /* + * finish command + */ + r = '\r'; + pwrite(FD, &r, 1); + do + read(FD, &c, 1); + while ((c&0177) != '\n'); + ioctl(0, TIOCSETC, &defchars); + + (void) setjmp(intbuf); + f = signal(SIGINT, intcopy); + start = time(0); + for (ct = 0; !quit;) { + eof = read(FD, &c, 1) <= 0; + c &= 0177; + if (quit) + continue; + if (eof || any(c, eofchars)) + break; + if (c == 0) + continue; /* ignore nulls */ + if (c == '\r') + continue; + *p++ = c; + + if (c == '\n' && boolean(value(VERBOSE))) + printf("\r%d", ++ct); + if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { + if (write(fd, buffer, cnt) != cnt) { + printf("\r\nwrite error\r\n"); + quit = 1; + } + p = buffer; + } + } + if (cnt = (p-buffer)) + if (write(fd, buffer, cnt) != cnt) + printf("\r\nwrite error\r\n"); + + if (boolean(value(VERBOSE))) + prtime(" lines transferred in ", time(0)-start); + ioctl(0, TIOCSETC, &tchars); + write(fildes[1], (char *)&ccc, 1); + signal(SIGINT, f); + close(fd); +} + +/* + * FTP - remote ==> local process + * send remote input to local process via pipe + */ +pipefile() +{ + int cpid, pdes[2]; + char buf[256]; + int status, p; + extern int errno; + + if (prompt("Local command? ", buf)) + return; + + if (pipe(pdes)) { + printf("can't establish pipe\r\n"); + return; + } + + if ((cpid = fork()) < 0) { + printf("can't fork!\r\n"); + return; + } else if (cpid) { + if (prompt("List command for remote system? ", buf)) { + close(pdes[0]), close(pdes[1]); + kill (cpid, SIGKILL); + } else { + close(pdes[0]); + signal(SIGPIPE, intcopy); + transfer(buf, pdes[1], value(EOFREAD)); + signal(SIGPIPE, SIG_DFL); + while ((p = wait(&status)) > 0 && p != cpid) + ; + } + } else { + register int f; + + dup2(pdes[0], 0); + close(pdes[0]); + for (f = 3; f < 20; f++) + close(f); + execute(buf); + printf("can't execl!\r\n"); + exit(0); + } +} + +/* + * Interrupt service routine for FTP + */ +void +stopsnd() +{ + + stop = 1; + signal(SIGINT, SIG_IGN); +} + +/* + * FTP - local ==> remote + * send local file to remote host + * terminate transmission with pseudo EOF sequence + */ +sendfile(cc) + char cc; +{ + FILE *fd; + char *fnamex; + char *expand(); + + putchar(cc); + /* + * get file name + */ + if (prompt("Local file name? ", fname)) + return; + + /* + * look up file + */ + fnamex = expand(fname); + if ((fd = fopen(fnamex, "r")) == NULL) { + printf("%s: cannot open\r\n", fname); + return; + } + transmit(fd, value(EOFWRITE), NULL); + if (!boolean(value(ECHOCHECK))) { + struct sgttyb buf; + + ioctl(FD, TIOCGETP, &buf); /* this does a */ + ioctl(FD, TIOCSETP, &buf); /* wflushtty */ + } +} + +/* + * Bulk transfer routine to remote host -- + * used by sendfile() and cu_put() + */ +transmit(fd, eofchars, command) + FILE *fd; + char *eofchars, *command; +{ + char *pc, lastc; + int c, ccount, lcount; + time_t start_t, stop_t; + sig_t f; + + kill(pid, SIGIOT); /* put TIPOUT into a wait state */ + stop = 0; + f = signal(SIGINT, stopsnd); + ioctl(0, TIOCSETC, &defchars); + read(repdes[0], (char *)&ccc, 1); + if (command != NULL) { + for (pc = command; *pc; pc++) + send(*pc); + if (boolean(value(ECHOCHECK))) + read(FD, (char *)&c, 1); /* trailing \n */ + else { + struct sgttyb buf; + + ioctl(FD, TIOCGETP, &buf); /* this does a */ + ioctl(FD, TIOCSETP, &buf); /* wflushtty */ + sleep(5); /* wait for remote stty to take effect */ + } + } + lcount = 0; + lastc = '\0'; + start_t = time(0); + while (1) { + ccount = 0; + do { + c = getc(fd); + if (stop) + goto out; + if (c == EOF) + goto out; + if (c == 0177 && !boolean(value(RAWFTP))) + continue; + lastc = c; + if (c < 040) { + if (c == '\n') { + if (!boolean(value(RAWFTP))) + c = '\r'; + } + else if (c == '\t') { + if (!boolean(value(RAWFTP))) { + if (boolean(value(TABEXPAND))) { + send(' '); + while ((++ccount % 8) != 0) + send(' '); + continue; + } + } + } else + if (!boolean(value(RAWFTP))) + continue; + } + send(c); + } while (c != '\r' && !boolean(value(RAWFTP))); + if (boolean(value(VERBOSE))) + printf("\r%d", ++lcount); + if (boolean(value(ECHOCHECK))) { + timedout = 0; + alarm((int)value(ETIMEOUT)); + do { /* wait for prompt */ + read(FD, (char *)&c, 1); + if (timedout || stop) { + if (timedout) + printf("\r\ntimed out at eol\r\n"); + alarm(0); + goto out; + } + } while ((c&0177) != character(value(PROMPT))); + alarm(0); + } + } +out: + if (lastc != '\n' && !boolean(value(RAWFTP))) + send('\r'); + for (pc = eofchars; *pc; pc++) + send(*pc); + stop_t = time(0); + fclose(fd); + signal(SIGINT, f); + if (boolean(value(VERBOSE))) + if (boolean(value(RAWFTP))) + prtime(" chars transferred in ", stop_t-start_t); + else + prtime(" lines transferred in ", stop_t-start_t); + write(fildes[1], (char *)&ccc, 1); + ioctl(0, TIOCSETC, &tchars); +} + +/* + * Cu-like put command + */ +cu_put(cc) + char cc; +{ + FILE *fd; + char line[BUFSIZ]; + int argc; + char *expand(); + char *copynamex; + + if (prompt("[put] ", copyname)) + return; + if ((argc = args(copyname, argv)) < 1 || argc > 2) { + printf("usage: from [to]\r\n"); + return; + } + if (argc == 1) + argv[1] = argv[0]; + copynamex = expand(argv[0]); + if ((fd = fopen(copynamex, "r")) == NULL) { + printf("%s: cannot open\r\n", copynamex); + return; + } + if (boolean(value(ECHOCHECK))) + sprintf(line, "cat>%s\r", argv[1]); + else + sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]); + transmit(fd, "\04", line); +} + +/* + * FTP - send single character + * wait for echo & handle timeout + */ +send(c) + char c; +{ + char cc; + int retry = 0; + + cc = c; + pwrite(FD, &cc, 1); +#ifdef notdef + if (number(value(CDELAY)) > 0 && c != '\r') + nap(number(value(CDELAY))); +#endif + if (!boolean(value(ECHOCHECK))) { +#ifdef notdef + if (number(value(LDELAY)) > 0 && c == '\r') + nap(number(value(LDELAY))); +#endif + return; + } +tryagain: + timedout = 0; + alarm((int)value(ETIMEOUT)); + read(FD, &cc, 1); + alarm(0); + if (timedout) { + printf("\r\ntimeout error (%s)\r\n", ctrl(c)); + if (retry++ > 3) + return; + pwrite(FD, &null, 1); /* poke it */ + goto tryagain; + } +} + +void +timeout() +{ + signal(SIGALRM, timeout); + timedout = 1; +} + +/* + * Stolen from consh() -- puts a remote file on the output of a local command. + * Identical to consh() except for where stdout goes. + */ +pipeout(c) +{ + char buf[256]; + int cpid, status, p; + time_t start; + + putchar(c); + if (prompt("Local command? ", buf)) + return; + kill(pid, SIGIOT); /* put TIPOUT into a wait state */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + ioctl(0, TIOCSETC, &defchars); + read(repdes[0], (char *)&ccc, 1); + /* + * Set up file descriptors in the child and + * let it go... + */ + if ((cpid = fork()) < 0) + printf("can't fork!\r\n"); + else if (cpid) { + start = time(0); + while ((p = wait(&status)) > 0 && p != cpid) + ; + } else { + register int i; + + dup2(FD, 1); + for (i = 3; i < 20; i++) + close(i); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + execute(buf); + printf("can't find `%s'\r\n", buf); + exit(0); + } + if (boolean(value(VERBOSE))) + prtime("away for ", time(0)-start); + write(fildes[1], (char *)&ccc, 1); + ioctl(0, TIOCSETC, &tchars); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); +} + +#ifdef CONNECT +/* + * Fork a program with: + * 0 <-> remote tty in + * 1 <-> remote tty out + * 2 <-> local tty out + */ +consh(c) +{ + char buf[256]; + int cpid, status, p; + time_t start; + + putchar(c); + if (prompt("Local command? ", buf)) + return; + kill(pid, SIGIOT); /* put TIPOUT into a wait state */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + ioctl(0, TIOCSETC, &defchars); + read(repdes[0], (char *)&ccc, 1); + /* + * Set up file descriptors in the child and + * let it go... + */ + if ((cpid = fork()) < 0) + printf("can't fork!\r\n"); + else if (cpid) { + start = time(0); + while ((p = wait(&status)) > 0 && p != cpid) + ; + } else { + register int i; + + dup2(FD, 0); + dup2(3, 1); + for (i = 3; i < 20; i++) + close(i); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + execute(buf); + printf("can't find `%s'\r\n", buf); + exit(0); + } + if (boolean(value(VERBOSE))) + prtime("away for ", time(0)-start); + write(fildes[1], (char *)&ccc, 1); + ioctl(0, TIOCSETC, &tchars); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); +} +#endif + +/* + * Escape to local shell + */ +shell() +{ + int shpid, status; + extern char **environ; + char *cp; + + printf("[sh]\r\n"); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + unraw(); + if (shpid = fork()) { + while (shpid != wait(&status)); + raw(); + printf("\r\n!\r\n"); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + return; + } else { + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + if ((cp = rindex(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + shell_uid(); + execl(value(SHELL), cp, 0); + printf("\r\ncan't execl!\r\n"); + exit(1); + } +} + +/* + * TIPIN portion of scripting + * initiate the conversation with TIPOUT + */ +setscript() +{ + char c; + /* + * enable TIPOUT side for dialogue + */ + kill(pid, SIGEMT); + if (boolean(value(SCRIPT))) + write(fildes[1], value(RECORD), size(value(RECORD))); + write(fildes[1], "\n", 1); + /* + * wait for TIPOUT to finish + */ + read(repdes[0], &c, 1); + if (c == 'n') + printf("can't create %s\r\n", value(RECORD)); +} + +/* + * Change current working directory of + * local portion of tip + */ +chdirectory() +{ + char dirname[80]; + register char *cp = dirname; + + if (prompt("[cd] ", dirname)) { + if (stoprompt) + return; + cp = value(HOME); + } + if (chdir(cp) < 0) + printf("%s: bad directory\r\n", cp); + printf("!\r\n"); +} + +tipabort(msg) + char *msg; +{ + + kill(pid, SIGTERM); + disconnect(msg); + if (msg != NOSTR) + printf("\r\n%s", msg); + printf("\r\n[EOT]\r\n"); + daemon_uid(); + (void)uu_unlock(uucplock); + unraw(); + exit(0); +} + +finish() +{ + char *dismsg; + + if ((dismsg = value(DISCONNECT)) != NOSTR) { + write(FD, dismsg, strlen(dismsg)); + sleep(5); + } + tipabort(NOSTR); +} + +void +intcopy() +{ + raw(); + quit = 1; + longjmp(intbuf, 1); +} + +execute(s) + char *s; +{ + register char *cp; + + if ((cp = rindex(value(SHELL), '/')) == NULL) + cp = value(SHELL); + else + cp++; + shell_uid(); + execl(value(SHELL), cp, "-c", s, 0); +} + +args(buf, a) + char *buf, *a[]; +{ + register char *p = buf, *start; + register char **parg = a; + register int n = 0; + + do { + while (*p && (*p == ' ' || *p == '\t')) + p++; + start = p; + if (*p) + *parg = p; + while (*p && (*p != ' ' && *p != '\t')) + p++; + if (p != start) + parg++, n++; + if (*p) + *p++ = '\0'; + } while (*p); + + return(n); +} + +prtime(s, a) + char *s; + time_t a; +{ + register i; + int nums[3]; + + for (i = 0; i < 3; i++) { + nums[i] = (int)(a % quant[i]); + a /= quant[i]; + } + printf("%s", s); + while (--i >= 0) + if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0) + printf("%d %s%c ", nums[i], sep[i], + nums[i] == 1 ? '\0' : 's'); + printf("\r\n!\r\n"); +} + +variable() +{ + char buf[256]; + + if (prompt("[set] ", buf)) + return; + vlex(buf); + if (vtable[BEAUTIFY].v_access&CHANGED) { + vtable[BEAUTIFY].v_access &= ~CHANGED; + kill(pid, SIGSYS); + } + if (vtable[SCRIPT].v_access&CHANGED) { + vtable[SCRIPT].v_access &= ~CHANGED; + setscript(); + /* + * So that "set record=blah script" doesn't + * cause two transactions to occur. + */ + if (vtable[RECORD].v_access&CHANGED) + vtable[RECORD].v_access &= ~CHANGED; + } + if (vtable[RECORD].v_access&CHANGED) { + vtable[RECORD].v_access &= ~CHANGED; + if (boolean(value(SCRIPT))) + setscript(); + } + if (vtable[TAND].v_access&CHANGED) { + vtable[TAND].v_access &= ~CHANGED; + if (boolean(value(TAND))) + tandem("on"); + else + tandem("off"); + } + if (vtable[LECHO].v_access&CHANGED) { + vtable[LECHO].v_access &= ~CHANGED; + HD = boolean(value(LECHO)); + } + if (vtable[PARITY].v_access&CHANGED) { + vtable[PARITY].v_access &= ~CHANGED; + setparity(); + } +} + +/* + * Turn tandem mode on or off for remote tty. + */ +tandem(option) + char *option; +{ + struct sgttyb rmtty; + + ioctl(FD, TIOCGETP, &rmtty); + if (strcmp(option,"on") == 0) { + rmtty.sg_flags |= TANDEM; + arg.sg_flags |= TANDEM; + } else { + rmtty.sg_flags &= ~TANDEM; + arg.sg_flags &= ~TANDEM; + } + ioctl(FD, TIOCSETP, &rmtty); + ioctl(0, TIOCSETP, &arg); +} + +/* + * Send a break. + */ +genbrk() +{ + + ioctl(FD, TIOCSBRK, NULL); + sleep(1); + ioctl(FD, TIOCCBRK, NULL); +} + +/* + * Suspend tip + */ +suspend(c) + char c; +{ + + unraw(); + kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); + raw(); +} + +/* + * expand a file name if it includes shell meta characters + */ + +char * +expand(name) + char name[]; +{ + static char xname[BUFSIZ]; + char cmdbuf[BUFSIZ]; + register int pid, l, rc; + register char *cp, *Shell; + int s, pivec[2], (*sigint)(); + + if (!anyof(name, "~{[*?$`'\"\\")) + return(name); + /* sigint = signal(SIGINT, SIG_IGN); */ + if (pipe(pivec) < 0) { + perror("pipe"); + /* signal(SIGINT, sigint) */ + return(name); + } + sprintf(cmdbuf, "echo %s", name); + if ((pid = vfork()) == 0) { + Shell = value(SHELL); + if (Shell == NOSTR) + Shell = _PATH_BSHELL; + close(pivec[0]); + close(1); + dup(pivec[1]); + close(pivec[1]); + close(2); + shell_uid(); + execl(Shell, Shell, "-c", cmdbuf, 0); + _exit(1); + } + if (pid == -1) { + perror("fork"); + close(pivec[0]); + close(pivec[1]); + return(NOSTR); + } + close(pivec[1]); + l = read(pivec[0], xname, BUFSIZ); + close(pivec[0]); + while (wait(&s) != pid); + ; + s &= 0377; + if (s != 0 && s != SIGPIPE) { + fprintf(stderr, "\"Echo\" failed\n"); + return(NOSTR); + } + if (l < 0) { + perror("read"); + return(NOSTR); + } + if (l == 0) { + fprintf(stderr, "\"%s\": No match\n", name); + return(NOSTR); + } + if (l == BUFSIZ) { + fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); + return(NOSTR); + } + xname[l] = 0; + for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) + ; + *++cp = '\0'; + return(xname); +} + +/* + * Are any of the characters in the two strings the same? + */ + +anyof(s1, s2) + register char *s1, *s2; +{ + register int c; + + while (c = *s1++) + if (any(c, s2)) + return(1); + return(0); +} diff --git a/usr.bin/tip/cmdtab.c b/usr.bin/tip/cmdtab.c new file mode 100644 index 0000000..f6bcb60 --- /dev/null +++ b/usr.bin/tip/cmdtab.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +extern int shell(), getfl(), sendfile(), chdirectory(); +extern int finish(), help(), pipefile(), pipeout(), consh(), variable(); +extern int cu_take(), cu_put(), dollar(), genbrk(), suspend(); + +esctable_t etable[] = { + { '!', NORM, "shell", shell }, + { '<', NORM, "receive file from remote host", getfl }, + { '>', NORM, "send file to remote host", sendfile }, + { 't', NORM, "take file from remote UNIX", cu_take }, + { 'p', NORM, "put file to remote UNIX", cu_put }, + { '|', NORM, "pipe remote file", pipefile }, + { '$', NORM, "pipe local command to remote host", pipeout }, +#ifdef CONNECT + { 'C', NORM, "connect program to remote host",consh }, +#endif + { 'c', NORM, "change directory", chdirectory }, + { '.', NORM, "exit from tip", finish }, + {CTRL('d'),NORM,"exit from tip", finish }, + {CTRL('y'),NORM,"suspend tip (local+remote)", suspend }, + {CTRL('z'),NORM,"suspend tip (local only)", suspend }, + { 's', NORM, "set variable", variable }, + { '?', NORM, "get this summary", help }, + { '#', NORM, "send break", genbrk }, + { 0, 0, 0 } +}; diff --git a/usr.bin/tip/cu.c b/usr.bin/tip/cu.c new file mode 100644 index 0000000..fae2b3c --- /dev/null +++ b/usr.bin/tip/cu.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)cu.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +void cleanup(); + +/* + * Botch the interface to look like cu's + */ +cumain(argc, argv) + char *argv[]; +{ + register int i; + static char sbuf[12]; + + if (argc < 2) { + printf("usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n"); + exit(8); + } + CU = DV = NOSTR; + BR = DEFBR; + for (; argc > 1; argv++, argc--) { + if (argv[1][0] != '-') + PN = argv[1]; + else switch (argv[1][1]) { + + case 't': + HW = 1, DU = -1; + --argc; + continue; + + case 'a': + CU = argv[2]; ++argv; --argc; + break; + + case 's': + if (argc < 3 || speed(atoi(argv[2])) == 0) { + fprintf(stderr, "cu: unsupported speed %s\n", + argv[2]); + exit(3); + } + BR = atoi(argv[2]); ++argv; --argc; + break; + + case 'l': + DV = argv[2]; ++argv; --argc; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (CU) + CU[strlen(CU)-1] = argv[1][1]; + if (DV) + DV[strlen(DV)-1] = argv[1][1]; + break; + + default: + printf("Bad flag %s", argv[1]); + break; + } + } + signal(SIGINT, cleanup); + signal(SIGQUIT, cleanup); + signal(SIGHUP, cleanup); + signal(SIGTERM, cleanup); + + /* + * The "cu" host name is used to define the + * attributes of the generic dialer. + */ + (void)sprintf(sbuf, "cu%d", BR); + if ((i = hunt(sbuf)) == 0) { + printf("all ports busy\n"); + exit(3); + } + if (i == -1) { + printf("link down\n"); + (void)uu_unlock(uucplock); + exit(3); + } + setbuf(stdout, NULL); + loginit(); + user_uid(); + vinit(); + setparity("none"); + boolean(value(VERBOSE)) = 0; + if (HW) + ttysetup(speed(BR)); + if (connect()) { + printf("Connect failed\n"); + daemon_uid(); + (void)uu_unlock(uucplock); + exit(1); + } + if (!HW) + ttysetup(speed(BR)); +} diff --git a/usr.bin/tip/hunt.c b/usr.bin/tip/hunt.c new file mode 100644 index 0000000..650ac26 --- /dev/null +++ b/usr.bin/tip/hunt.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)hunt.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +extern char *getremote(); +extern char *rindex(); + +static jmp_buf deadline; +static int deadfl; + +void +dead() +{ + deadfl = 1; + longjmp(deadline, 1); +} + +hunt(name) + char *name; +{ + register char *cp; + sig_t f; + + f = signal(SIGALRM, dead); + while (cp = getremote(name)) { + deadfl = 0; + uucplock = rindex(cp, '/')+1; + if (uu_lock(uucplock) < 0) + continue; + /* + * Straight through call units, such as the BIZCOMP, + * VADIC and the DF, must indicate they're hardwired in + * order to get an open file descriptor placed in FD. + * Otherwise, as for a DN-11, the open will have to + * be done in the "open" routine. + */ + if (!HW) + break; + if (setjmp(deadline) == 0) { + alarm(10); + FD = open(cp, O_RDWR); + } + alarm(0); + if (FD < 0) { + perror(cp); + deadfl = 1; + } + if (!deadfl) { + ioctl(FD, TIOCEXCL, 0); + ioctl(FD, TIOCHPCL, 0); + signal(SIGALRM, SIG_DFL); + return ((int)cp); + } + (void)uu_unlock(uucplock); + } + signal(SIGALRM, f); + return (deadfl ? -1 : (int)cp); +} diff --git a/usr.bin/tip/log.c b/usr.bin/tip/log.c new file mode 100644 index 0000000..5da2c45 --- /dev/null +++ b/usr.bin/tip/log.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)log.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +#ifdef ACULOG +static FILE *flog = NULL; + +/* + * Log file maintenance routines + */ + +logent(group, num, acu, message) + char *group, *num, *acu, *message; +{ + char *user, *timestamp; + struct passwd *pwd; + long t; + + if (flog == NULL) + return; + if (flock(fileno(flog), LOCK_EX) < 0) { + perror("tip: flock"); + return; + } + if ((user = getlogin()) == NOSTR) + if ((pwd = getpwuid(getuid())) == NOPWD) + user = "???"; + else + user = pwd->pw_name; + t = time(0); + timestamp = ctime(&t); + timestamp[24] = '\0'; + fprintf(flog, "%s (%s) <%s, %s, %s> %s\n", + user, timestamp, group, +#ifdef PRISTINE + "", +#else + num, +#endif + acu, message); + (void) fflush(flog); + (void) flock(fileno(flog), LOCK_UN); +} + +loginit() +{ + flog = fopen(value(LOG), "a"); + if (flog == NULL) + fprintf(stderr, "can't open log file %s.\r\n", value(LOG)); +} +#endif diff --git a/usr.bin/tip/partab.c b/usr.bin/tip/partab.c new file mode 100644 index 0000000..1da4e23 --- /dev/null +++ b/usr.bin/tip/partab.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)partab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Even parity table for 0-0177 + */ +char evenpartab[] = { + 0000,0201,0202,0003,0204,0005,0006,0207, + 0210,0011,0012,0213,0014,0215,0216,0017, + 0220,0021,0022,0223,0024,0225,0226,0027, + 0030,0231,0232,0033,0234,0035,0036,0237, + 0240,0041,0042,0243,0044,0245,0246,0047, + 0050,0251,0252,0053,0254,0055,0056,0257, + 0060,0261,0262,0063,0264,0065,0066,0267, + 0270,0071,0072,0273,0074,0275,0276,0077, + 0300,0101,0102,0303,0104,0305,0306,0107, + 0110,0311,0312,0113,0314,0115,0116,0317, + 0120,0321,0322,0123,0324,0125,0126,0327, + 0330,0131,0132,0333,0134,0335,0336,0137, + 0140,0341,0342,0143,0344,0145,0146,0347, + 0350,0151,0152,0353,0154,0355,0356,0157, + 0360,0161,0162,0363,0164,0365,0366,0167, + 0170,0371,0372,0173,0374,0175,0176,0377, +}; diff --git a/usr.bin/tip/pathnames.h b/usr.bin/tip/pathnames.h new file mode 100644 index 0000000..b58251d --- /dev/null +++ b/usr.bin/tip/pathnames.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +#define _PATH_ACULOG "/var/log/aculog" +#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK..%s" +#ifdef notdef +#define _PATH_LOCKDIRNAME "/var/spool/uucp/LCK/LCK..%s" +#endif +#define _PATH_PHONES "/etc/phones" +#define _PATH_REMOTE "/etc/remote" diff --git a/usr.bin/tip/remcap.c b/usr.bin/tip/remcap.c new file mode 100644 index 0000000..7a7e0c2 --- /dev/null +++ b/usr.bin/tip/remcap.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)remcap.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * remcap - routines for dealing with the remote host data base + * + * derived from termcap + */ +#include +#include +#include +#include +#include "pathnames.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif +#define MAXHOP 32 /* max number of tc= indirections */ + +#define tgetent rgetent +#define tnchktc rnchktc +#define tnamatch rnamatch +#define tgetnum rgetnum +#define tgetflag rgetflag +#define tgetstr rgetstr +#define E_TERMCAP RM = _PATH_REMOTE +#define V_TERMCAP "REMOTE" +#define V_TERM "HOST" + +char *RM; + +/* + * termcap - routines for dealing with the terminal capability data base + * + * BUG: Should use a "last" pointer in tbuf, so that searching + * for capabilities alphabetically would not be a n**2/2 + * process when large numbers of capabilities are given. + * Note: If we add a last pointer now we will screw up the + * tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities. We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static char *tbuf; +static int hopcount; /* detect infinite loops in termcap, init 0 */ +static char *tskip(); +char *tgetstr(); +static char *tdecode(); +static char *remotefile; + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +tgetent(bp, name) + char *bp, *name; +{ + char lbuf[BUFSIZ], *cp, *p; + int rc1, rc2; + + remotefile = cp = getenv(V_TERMCAP); + if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) { + remotefile = cp = _PATH_REMOTE; + return (getent(bp, name, cp)); + } else { + if ((rc1 = getent(bp, name, cp)) != 1) + *bp = '\0'; + remotefile = cp = _PATH_REMOTE; + rc2 = getent(lbuf, name, cp); + if (rc1 != 1 && rc2 != 1) + return (rc2); + if (rc2 == 1) { + p = lbuf; + if (rc1 == 1) + while (*p++ != ':') + ; + if (strlen(bp) + strlen(p) > BUFSIZ) { + write(2, "Remcap entry too long\n", 23); + return (-1); + } + strcat(bp, p); + } + tbuf = bp; + return (1); + } +} + +getent(bp, name, cp) + char *bp, *name, *cp; +{ + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ], *cp2; + int tf; + + tbuf = bp; + tf = 0; + /* + * TERMCAP can have one of two things in it. It can be the + * name of a file to use instead of /etc/termcap. In this + * case it better start with a "/". Or it can be an entry to + * use so we don't have to read the file. In this case it + * has to already have the newlines crunched out. + */ + if (cp && *cp) { + if (*cp!='/') { + cp2 = getenv(V_TERM); + if (cp2 == (char *)0 || strcmp(name,cp2) == 0) { + strcpy(bp,cp); + return (tnchktc()); + } else + tf = open(E_TERMCAP, O_RDONLY); + } else + tf = open(RM = cp, O_RDONLY); + } + if (tf == 0) + tf = open(E_TERMCAP, O_RDONLY); + if (tf < 0) + return (-1); + for (;;) { + cp = bp; + for (;;) { + if (i == cnt) { + cnt = read(tf, ibuf, BUFSIZ); + if (cnt <= 0) { + close(tf); + return (0); + } + i = 0; + } + c = ibuf[i++]; + if (c == '\n') { + if (cp > bp && cp[-1] == '\\') { + cp--; + continue; + } + break; + } + if (cp >= bp+BUFSIZ) { + write(2,"Remcap entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return (tnchktc()); + } + } +} + +/* + * tnchktc: check the last entry, see if it's tc=xxx. If so, + * recursively find xxx and append that entry (minus the names) + * to take the place of the tc=xxx entry. This allows termcap + * entries to say "like an HP2621 but doesn't turn on the labels". + * Note that this works because of the left to right scan. + */ +tnchktc() +{ + register char *p, *q; + char tcname[16]; /* name of similar terminal */ + char tcbuf[BUFSIZ]; + char *holdtbuf = tbuf; + int l; + char *cp; + + p = tbuf + strlen(tbuf) - 2; /* before the last colon */ + while (*--p != ':') + if (p MAXHOP) { + write(2, "Infinite tc= loop\n", 18); + return (0); + } + if (getent(tcbuf, tcname, remotefile) != 1) { + if (strcmp(remotefile, _PATH_REMOTE) == 0) + return (0); + else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1) + return (0); + } + for (q = tcbuf; *q++ != ':'; ) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Remcap entry too long\n", 23); + q[BUFSIZ - (p-holdtbuf)] = 0; + } + strcpy(p, q); + tbuf = holdtbuf; + return (1); +} + +/* + * Tnamatch deals with name matching. The first field of the termcap + * entry is a sequence of names separated by |'s, so we compare + * against each such name. The normal : terminator after the last + * name (before the first field) stops us. + */ +tnamatch(np) + char *np; +{ + register char *Np, *Bp; + + Bp = tbuf; + if (*Bp == '#') + return (0); + for (;;) { + for (Np = np; *Np && *Bp == *Np; Bp++, Np++) + continue; + if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) + return (1); + while (*Bp && *Bp != ':' && *Bp != '|') + Bp++; + if (*Bp == 0 || *Bp == ':') + return (0); + Bp++; + } +} + +/* + * Skip to the next field. Notice that this is very dumb, not + * knowing about \: escapes or any such. If necessary, :'s can be put + * into the termcap file in octal. + */ +static char * +tskip(bp) + register char *bp; +{ + + while (*bp && *bp != ':') + bp++; + if (*bp == ':') + bp++; + return (bp); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + * li#80 + * i.e. the option string is separated from the numeric value by + * a # character. If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +tgetnum(id) + char *id; +{ + register int i, base; + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (*bp == 0) + return (-1); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return (-1); + if (*bp != '#') + continue; + bp++; + base = 10; + if (*bp == '0') + base = 8; + i = 0; + while (isdigit(*bp)) + i *= base, i += *bp++ - '0'; + return (i); + } +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer. Return 1 if we find the option, or 0 if it is + * not given. + */ +tgetflag(id) + char *id; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { + if (!*bp || *bp == ':') + return (1); + else if (*bp == '@') + return (0); + } + } +} + +/* + * Get a string valued option. + * These are given as + * cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) + char *id, **area; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return (0); + if (*bp != '=') + continue; + bp++; + return (tdecode(bp, area)); + } +} + +/* + * Tdecode does the grung work to decode the + * string capability escapes. + */ +static char * +tdecode(str, area) + register char *str; + char **area; +{ + register char *cp; + register int c; + register char *dp; + int i; + + cp = *area; + while ((c = *str++) && c != ':') { + switch (c) { + + case '^': + c = *str++ & 037; + break; + + case '\\': + dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; + c = *str++; +nextc: + if (*dp++ == c) { + c = *dp++; + break; + } + dp++; + if (*dp) + goto nextc; + if (isdigit(c)) { + c -= '0', i = 2; + do + c <<= 3, c |= *str++ - '0'; + while (--i && isdigit(*str)); + } + break; + } + *cp++ = c; + } + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} diff --git a/usr.bin/tip/remote.c b/usr.bin/tip/remote.c new file mode 100644 index 0000000..9b86066 --- /dev/null +++ b/usr.bin/tip/remote.c @@ -0,0 +1,226 @@ +/* + * 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 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[] = "@(#)remote.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include "pathnames.h" +#include "tip.h" + +/* + * Attributes to be gleened from remote host description + * data base. + */ +static char **caps[] = { + &AT, &DV, &CM, &CU, &EL, &IE, &OE, &PN, &PR, &DI, + &ES, &EX, &FO, &RC, &RE, &PA +}; + +static char *capstrings[] = { + "at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr", + "di", "es", "ex", "fo", "rc", "re", "pa", 0 +}; + +static char *db_array[3] = { _PATH_REMOTE, 0, 0 }; + +#define cgetflag(f) (cgetcap(bp, f, ':') != NULL) + +static +getremcap(host) + register char *host; +{ + register char **p, ***q; + char *bp; + char *rempath; + int stat; + + rempath = getenv("REMOTE"); + if (rempath != NULL) + if (*rempath != '/') + /* we have an entry */ + cgetset(rempath); + else { /* we have a path */ + db_array[1] = rempath; + db_array[2] = _PATH_REMOTE; + } + + if ((stat = cgetent(&bp, db_array, host)) < 0) { + if (DV || + host[0] == '/' && access(DV = host, R_OK | W_OK) == 0) { + CU = DV; + HO = host; + HW = 1; + DU = 0; + if (!BR) + BR = DEFBR; + FS = DEFFS; + return; + } + switch(stat) { + case -1: + fprintf(stderr, "tip: unknown host %s\n", host); + break; + case -2: + fprintf(stderr, + "tip: can't open host description file\n"); + break; + case -3: + fprintf(stderr, + "tip: possible reference loop in host description file\n"); + break; + } + exit(3); + } + + for (p = capstrings, q = caps; *p != NULL; p++, q++) + if (**q == NULL) + cgetstr(bp, *p, *q); + if (!BR && (cgetnum(bp, "br", &BR) == -1)) + BR = DEFBR; + if (cgetnum(bp, "fs", &FS) == -1) + FS = DEFFS; + if (DU < 0) + DU = 0; + else + DU = cgetflag("du"); + if (DV == NOSTR) { + fprintf(stderr, "%s: missing device spec\n", host); + exit(3); + } + if (DU && CU == NOSTR) + CU = DV; + if (DU && PN == NOSTR) { + fprintf(stderr, "%s: missing phone number\n", host); + exit(3); + } + + HD = cgetflag("hd"); + + /* + * This effectively eliminates the "hw" attribute + * from the description file + */ + if (!HW) + HW = (CU == NOSTR) || (DU && equal(DV, CU)); + HO = host; + /* + * see if uppercase mode should be turned on initially + */ + if (cgetflag("ra")) + boolean(value(RAISE)) = 1; + if (cgetflag("ec")) + boolean(value(ECHOCHECK)) = 1; + if (cgetflag("be")) + boolean(value(BEAUTIFY)) = 1; + if (cgetflag("nb")) + boolean(value(BEAUTIFY)) = 0; + if (cgetflag("sc")) + boolean(value(SCRIPT)) = 1; + if (cgetflag("tb")) + boolean(value(TABEXPAND)) = 1; + if (cgetflag("vb")) + boolean(value(VERBOSE)) = 1; + if (cgetflag("nv")) + boolean(value(VERBOSE)) = 0; + if (cgetflag("ta")) + boolean(value(TAND)) = 1; + if (cgetflag("nt")) + boolean(value(TAND)) = 0; + if (cgetflag("rw")) + boolean(value(RAWFTP)) = 1; + if (cgetflag("hd")) + boolean(value(HALFDUPLEX)) = 1; + if (RE == NOSTR) + RE = (char *)"tip.record"; + if (EX == NOSTR) + EX = (char *)"\t\n\b\f"; + if (ES != NOSTR) + vstring("es", ES); + if (FO != NOSTR) + vstring("fo", FO); + if (PR != NOSTR) + vstring("pr", PR); + if (RC != NOSTR) + vstring("rc", RC); + if (cgetnum(bp, "dl", &DL) == -1) + DL = 0; + if (cgetnum(bp, "cl", &CL) == -1) + CL = 0; + if (cgetnum(bp, "et", &ET) == -1) + ET = 10; +} + +char * +getremote(host) + char *host; +{ + register char *cp; + static char *next; + static int lookedup = 0; + + if (!lookedup) { + if (host == NOSTR && (host = getenv("HOST")) == NOSTR) { + fprintf(stderr, "tip: no host specified\n"); + exit(3); + } + getremcap(host); + next = DV; + lookedup++; + } + /* + * We return a new device each time we're called (to allow + * a rotary action to be simulated) + */ + if (next == NOSTR) + return (NOSTR); + if ((cp = index(next, ',')) == NULL) { + DV = next; + next = NOSTR; + } else { + *cp++ = '\0'; + DV = next; + next = cp; + } + return (DV); +} diff --git a/usr.bin/tip/tip.1 b/usr.bin/tip/tip.1 new file mode 100644 index 0000000..10b8a3e --- /dev/null +++ b/usr.bin/tip/tip.1 @@ -0,0 +1,451 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tip.1 8.4 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt TIP 1 +.Os BSD 4 +.Sh NAME +.Nm tip , +.Nm cu +.Nd connect to a remote system +.Sh SYNOPSIS +.Nm tip +.Op Fl v +.Fl Ns Ns Ar speed +.Ar system\-name +.Nm tip +.Op Fl v +.Fl Ns Ns Ar speed +.Ar phone\-number +.Nm cu +.Ar phone\-number +.Op Fl t +.Op Fl s Ar speed +.Op Fl a Ar acu +.Op Fl l Ar line +.Op Fl # +.Sh DESCRIPTION +.Nm Tip +and +.Ar cu +establish a full-duplex connection to another machine, +giving the appearance of being logged in directly on the +remote cpu. It goes without saying that you must have a login +on the machine (or equivalent) to which you wish to connect. +The preferred interface is +.Nm tip . +The +.Ar cu +interface is included for those people attached to the +``call +.Ux Ns '' +command of version 7. This manual page +describes only +.Nm tip . +.Pp +Available Option: +.Bl -tag -width indent +.It Fl v +Set verbose mode. +.El +.Pp +Typed characters are normally transmitted directly to the remote +machine (which does the echoing as well). A tilde (`~') appearing +as the first character of a line is an escape signal; the following +are recognized: +.Bl -tag -width flag +.It Ic \&~^D No or Ic \&~ . +Drop the connection and exit +(you may still be logged in on the +remote machine). +.It Ic \&~c Op Ar name +Change directory to +.Ar name +(no argument +implies change to your home directory). +.It Ic \&~! +Escape to a shell (exiting the shell will +return you to tip). +.It Ic \&~> +Copy file from local to remote. +.Nm Tip +prompts for the name of a local file to transmit. +.It Ic \&~< +Copy file from remote to local. +.Nm Tip +prompts first for the name of the file to be sent, then for +a command to be executed on the remote machine. +.It Ic \&~p Ar from Op Ar to +Send a file to a remote +.Ux +host. The put command causes the remote +.Ux +system to run the command string ``cat > 'to''', while +.Nm tip +sends it the ``from'' +file. If the ``to'' file isn't specified the ``from'' file name is used. +This command is actually a +.Ux +specific version of the ``~>'' command. +.It Ic \&~t Ar from Op Ar to +Take a file from a remote +.Ux +host. +As in the put command the ``to'' file +defaults to the ``from'' file name if it isn't specified. +The remote host +executes the command string ``cat 'from';echo ^A'' to send the file to +.Nm tip . +.It Ic \&~| +Pipe the output from a remote command to a local +.Ux +process. +The command string sent to the local +.Ux +system is processed by the shell. +.It Ic \&~$ +Pipe the output from a local +.Ux +process to the remote host. +The command string sent to the local +.Ux +system is processed by the shell. +.It Ic \&~C +Fork a child process on the local system to perform special protocols +such as \s-1XMODEM\s+1. The child program will be run with the following +somewhat unusual arrangement of file descriptors: +.nf +.in +1i +0 <-> local tty in +1 <-> local tty out +2 <-> local tty out +3 <-> remote tty in +4 <-> remote tty out +.in -1i +.fi +.It Ic \&~# +Send a +.Dv BREAK +to the remote system. +For systems which don't support the +necessary +.Ar ioctl +call the break is simulated by a sequence of line speed changes +and +.Dv DEL +characters. +.It Ic \&~s +Set a variable (see the discussion below). +.It Ic \&~^Z +Stop +.Nm tip +(only available with job control). +.It Ic \&~^Y +Stop only the ``local side'' of +.Nm tip +(only available with job control); +the ``remote side'' of +.Nm tip , +the side that displays output from the remote host, is left running. +.It Ic \&~? +Get a summary of the tilde escapes +.El +.Pp +.Nm Tip +uses the file +.Pa /etc/remote +to find how to reach a particular +system and to find out how it should operate while talking +to the system; +refer to +.Xr remote 5 +for a full description. +Each system has a default baud rate with which to +establish a connection. If this value is not suitable, the baud rate +to be used may be specified on the command line, e.g. +.Ql "tip -300 mds" . +.Pp +When +.Nm tip +establishes a connection it sends out a +connection message to the remote system; the default value, if any, +is defined in +.Pa /etc/remote +(see +.Xr remote 5 ) . +.Pp +When +.Nm tip +prompts for an argument (e.g. during setup of +a file transfer) the line typed may be edited with the standard +erase and kill characters. A null line in response to a prompt, +or an interrupt, will abort the dialogue and return you to the +remote machine. +.Pp +.Nm Tip +guards against multiple users connecting to a remote system +by opening modems and terminal lines with exclusive access, +and by honoring the locking protocol used by +.Xr uucico 8 . +.Pp +During file transfers +.Nm tip +provides a running count of the number of lines transferred. +When using the ~> and ~< commands, the ``eofread'' and ``eofwrite'' +variables are used to recognize end-of-file when reading, and +specify end-of-file when writing (see below). File transfers +normally depend on tandem mode for flow control. If the remote +system does not support tandem mode, ``echocheck'' may be set +to indicate +.Nm tip +should synchronize with the remote system on the echo of each +transmitted character. +.Pp +When +.Nm tip +must dial a phone number to connect to a system it will print +various messages indicating its actions. +.Nm Tip +supports the +.Tn DEC DN Ns-11 +and +Racal-Vadic 831 auto-call-units; +the +.Tn DEC DF Ns \&02 +and +.Tn DF Ns \&03 , +Ventel 212+, Racal-Vadic 3451, and +Bizcomp 1031 and 1032 integral call unit/modems. +.Ss VARIABLES +.Nm Tip +maintains a set of +.Ar variables +which control its operation. +Some of these variables are read-only to normal users (root is allowed +to change anything of interest). Variables may be displayed +and set through the ``s'' escape. The syntax for variables is patterned +after +.Xr vi 1 +and +.Xr Mail 1 . +Supplying ``all'' +as an argument to the set command displays all variables readable by +the user. Alternatively, the user may request display of a particular +variable by attaching a `?' to the end. For example ``escape?'' +displays the current escape character. +.Pp +Variables are numeric, string, character, or boolean values. Boolean +variables are set merely by specifying their name; they may be reset +by prepending a `!' to the name. Other variable types are set by +concatenating an `=' and the value. The entire assignment must not +have any blanks in it. A single set command may be used to interrogate +as well as set a number of variables. +Variables may be initialized at run time by placing set commands +(without the ``~s'' prefix in a file +.Pa .tiprc +in one's home directory). The +.Fl v +option causes +.Nm tip +to display the sets as they are made. +Certain common variables have abbreviations. +The following is a list of common variables, +their abbreviations, and their default values. +.Bl -tag -width Ar +.It Ar beautify +(bool) Discard unprintable characters when a session is being scripted; +abbreviated +.Ar be . +.It Ar baudrate +(num) The baud rate at which the connection was established; +abbreviated +.Ar ba . +.It Ar dialtimeout +(num) When dialing a phone number, the time (in seconds) +to wait for a connection to be established; abbreviated +.Ar dial . +.It Ar echocheck +(bool) Synchronize with the remote host during file transfer by +waiting for the echo of the last character transmitted; default is +.Ar off . +.It Ar eofread +(str) The set of characters which signify an end-of-transmission +during a ~< file transfer command; abbreviated +.Ar eofr . +.It Ar eofwrite +(str) The string sent to indicate end-of-transmission during +a ~> file transfer command; abbreviated +.Ar eofw . +.It Ar eol +(str) The set of characters which indicate an end-of-line. +.Nm Tip +will recognize escape characters only after an end-of-line. +.It Ar escape +(char) The command prefix (escape) character; abbreviated +.Ar es ; +default value is `~'. +.It Ar exceptions +(str) The set of characters which should not be discarded +due to the beautification switch; abbreviated +.Ar ex ; +default value is ``\et\en\ef\eb''. +.It Ar force +(char) The character used to force literal data transmission; +abbreviated +.Ar fo ; +default value is `^P'. +.It Ar framesize +(num) The amount of data (in bytes) to buffer between file system +writes when receiving files; abbreviated +.Ar fr . +.It Ar host +(str) The name of the host to which you are connected; abbreviated +.Ar ho . +.It Ar prompt +(char) The character which indicates an end-of-line on the remote +host; abbreviated +.Ar pr ; +default value is `\en'. This value is used to synchronize during +data transfers. The count of lines transferred during a file transfer +command is based on receipt of this character. +.It Ar raise +(bool) Upper case mapping mode; abbreviated +.Ar ra ; +default value is +.Ar off . +When this mode is enabled, all lower case letters will be mapped to +upper case by +.Nm tip +for transmission to the remote machine. +.It Ar raisechar +(char) The input character used to toggle upper case mapping mode; +abbreviated +.Ar rc ; +default value is `^A'. +.It Ar record +(str) The name of the file in which a session script is recorded; +abbreviated +.Ar rec ; +default value is ``tip.record''. +.It Ar script +(bool) Session scripting mode; abbreviated +.Ar sc ; +default is +.Ar off . +When +.Ar script +is +.Li true , +.Nm tip +will record everything transmitted by the remote machine in +the script record file specified in +.Ar record . +If the +.Ar beautify +switch is on, only printable +.Tn ASCII +characters will be included in +the script file (those characters betwee 040 and 0177). The +variable +.Ar exceptions +is used to indicate characters which are an exception to the normal +beautification rules. +.It Ar tabexpand +(bool) Expand tabs to spaces during file transfers; abbreviated +.Ar tab ; +default value is +.Ar false . +Each tab is expanded to 8 spaces. +.It Ar verbose +(bool) Verbose mode; abbreviated +.Ar verb ; +default is +.Ar true . +When verbose mode is enabled, +.Nm tip +prints messages while dialing, shows the current number +of lines transferred during a file transfer operations, +and more. +.El +.Sh ENVIRONMENT +.Nm Tip +uses the following environment variables: +.Bl -tag -width Fl +.It Ev SHELL +(str) The name of the shell to use for the ~! command; default +value is ``/bin/sh'', or taken from the environment. +.It Ev HOME +(str) The home directory to use for the ~c command; default +value is taken from the environment. +.It Ev HOST +Check for a default host if none specified. +.El +.Pp +The variables +.Ev ${REMOTE} +and +.Ev ${PHONES} +are also exported. +.Sh FILES +.Bl -tag -width /var/spool/uucp/LCK..* -compact +.It Pa /etc/remote +Global system descriptions. +.It Pa /etc/phones +Global phone number data base. +.It ${REMOTE} +Private system descriptions. +.It ${PHONES} +Private phone numbers. +.It ~/.tiprc +Initialization file. +.It Pa tip.record +Record file. +.It /var/log/aculog +Line access log. +.It Pa /var/spool/uucp/LCK..* +Lock file to avoid conflicts with +.Xr uucp . +.El +.Sh DIAGNOSTICS +Diagnostics are, hopefully, self explanatory. +.Sh SEE ALSO +.Xr remote 5 , +.Xr phones 5 +.Sh HISTORY +The +.Nm tip +appeared command in +.Bx 4.2 . +.Sh BUGS +The full set of variables is undocumented and should, probably, be +pared down. diff --git a/usr.bin/tip/tip.c b/usr.bin/tip/tip.c new file mode 100644 index 0000000..b09cde7 --- /dev/null +++ b/usr.bin/tip/tip.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 1983, 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 copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * tip - UNIX link to other systems + * tip [-v] [-speed] system-name + * or + * cu phone-number [-s speed] [-l line] [-a acu] + */ +#include "tip.h" +#include "pathnames.h" + +/* + * Baud rate mapping table + */ +int bauds[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, + 1200, 1800, 2400, 4800, 9600, 19200, -1 +}; + +int disc = OTTYDISC; /* tip normally runs this way */ +void intprompt(); +void timeout(); +void cleanup(); +char *sname(); +char PNbuf[256]; /* This limits the size of a number */ + +main(argc, argv) + char *argv[]; +{ + char *system = NOSTR; + register int i; + register char *p; + char sbuf[12]; + + gid = getgid(); + egid = getegid(); + uid = getuid(); + euid = geteuid(); + if (equal(sname(argv[0]), "cu")) { + cumode = 1; + cumain(argc, argv); + goto cucommon; + } + + if (argc > 4) { + fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n"); + exit(1); + } + if (!isatty(0)) { + fprintf(stderr, "tip: must be interactive\n"); + exit(1); + } + + for (; argc > 1; argv++, argc--) { + if (argv[1][0] != '-') + system = argv[1]; + else switch (argv[1][1]) { + + case 'v': + vflag++; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + BR = atoi(&argv[1][1]); + break; + + default: + fprintf(stderr, "tip: %s, unknown option\n", argv[1]); + break; + } + } + + if (system == NOSTR) + goto notnumber; + if (isalpha(*system)) + goto notnumber; + /* + * System name is really a phone number... + * Copy the number then stomp on the original (in case the number + * is private, we don't want 'ps' or 'w' to find it). + */ + if (strlen(system) > sizeof PNbuf - 1) { + fprintf(stderr, "tip: phone number too long (max = %d bytes)\n", + sizeof PNbuf - 1); + exit(1); + } + strncpy( PNbuf, system, sizeof PNbuf - 1 ); + for (p = system; *p; p++) + *p = '\0'; + PN = PNbuf; + (void)sprintf(sbuf, "tip%d", BR); + system = sbuf; + +notnumber: + (void)signal(SIGINT, cleanup); + (void)signal(SIGQUIT, cleanup); + (void)signal(SIGHUP, cleanup); + (void)signal(SIGTERM, cleanup); + + if ((i = hunt(system)) == 0) { + printf("all ports busy\n"); + exit(3); + } + if (i == -1) { + printf("link down\n"); + (void)uu_unlock(uucplock); + exit(3); + } + setbuf(stdout, NULL); + loginit(); + + /* + * Kludge, their's no easy way to get the initialization + * in the right order, so force it here + */ + if ((PH = getenv("PHONES")) == NOSTR) + PH = _PATH_PHONES; + vinit(); /* init variables */ + setparity("even"); /* set the parity table */ + if ((i = speed(number(value(BAUDRATE)))) == NULL) { + printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); + (void)uu_unlock(uucplock); + exit(3); + } + + /* + * Now that we have the logfile and the ACU open + * return to the real uid and gid. These things will + * be closed on exit. Swap real and effective uid's + * so we can get the original permissions back + * for removing the uucp lock. + */ + user_uid(); + + /* + * Hardwired connections require the + * line speed set before they make any transmissions + * (this is particularly true of things like a DF03-AC) + */ + if (HW) + ttysetup(i); + if (p = connect()) { + printf("\07%s\n[EOT]\n", p); + daemon_uid(); + (void)uu_unlock(uucplock); + exit(1); + } + if (!HW) + ttysetup(i); +cucommon: + /* + * From here down the code is shared with + * the "cu" version of tip. + */ + + ioctl(0, TIOCGETP, (char *)&defarg); + ioctl(0, TIOCGETC, (char *)&defchars); + ioctl(0, TIOCGLTC, (char *)&deflchars); + ioctl(0, TIOCGETD, (char *)&odisc); + arg = defarg; + arg.sg_flags = ANYP | CBREAK; + tchars = defchars; + tchars.t_intrc = tchars.t_quitc = -1; + ltchars = deflchars; + ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc + = ltchars.t_lnextc = -1; + raw(); + + pipe(fildes); pipe(repdes); + (void)signal(SIGALRM, timeout); + + /* + * Everything's set up now: + * connection established (hardwired or dialup) + * line conditioned (baud rate, mode, etc.) + * internal data structures (variables) + * so, fork one process for local side and one for remote. + */ + printf(cumode ? "Connected\r\n" : "\07connected\r\n"); + if (pid = fork()) + tipin(); + else + tipout(); + /*NOTREACHED*/ +} + +void +cleanup() +{ + + daemon_uid(); + (void)uu_unlock(uucplock); + if (odisc) + ioctl(0, TIOCSETD, (char *)&odisc); + exit(0); +} + +/* + * Muck with user ID's. We are setuid to the owner of the lock + * directory when we start. user_uid() reverses real and effective + * ID's after startup, to run with the user's permissions. + * daemon_uid() switches back to the privileged uid for unlocking. + * Finally, to avoid running a shell with the wrong real uid, + * shell_uid() sets real and effective uid's to the user's real ID. + */ +static int uidswapped; + +user_uid() +{ + if (uidswapped == 0) { + seteuid(uid); + uidswapped = 1; + } +} + +daemon_uid() +{ + + if (uidswapped) { + seteuid(euid); + uidswapped = 0; + } +} + +shell_uid() +{ + + seteuid(uid); +} + +/* + * put the controlling keyboard into raw mode + */ +raw() +{ + + ioctl(0, TIOCSETP, &arg); + ioctl(0, TIOCSETC, &tchars); + ioctl(0, TIOCSLTC, <chars); + ioctl(0, TIOCSETD, (char *)&disc); +} + + +/* + * return keyboard to normal mode + */ +unraw() +{ + + ioctl(0, TIOCSETD, (char *)&odisc); + ioctl(0, TIOCSETP, (char *)&defarg); + ioctl(0, TIOCSETC, (char *)&defchars); + ioctl(0, TIOCSLTC, (char *)&deflchars); +} + +static jmp_buf promptbuf; + +/* + * Print string ``s'', then read a string + * in from the terminal. Handles signals & allows use of + * normal erase and kill characters. + */ +prompt(s, p) + char *s; + register char *p; +{ + register char *b = p; + sig_t oint, oquit; + + stoprompt = 0; + oint = signal(SIGINT, intprompt); + oquit = signal(SIGQUIT, SIG_IGN); + unraw(); + printf("%s", s); + if (setjmp(promptbuf) == 0) + while ((*p = getchar()) != EOF && *p != '\n') + p++; + *p = '\0'; + + raw(); + (void)signal(SIGINT, oint); + (void)signal(SIGQUIT, oquit); + return (stoprompt || p == b); +} + +/* + * Interrupt service routine during prompting + */ +void +intprompt() +{ + + (void)signal(SIGINT, SIG_IGN); + stoprompt = 1; + printf("\r\n"); + longjmp(promptbuf, 1); +} + +/* + * ****TIPIN TIPIN**** + */ +tipin() +{ + char gch, bol = 1; + + /* + * Kinda klugey here... + * check for scripting being turned on from the .tiprc file, + * but be careful about just using setscript(), as we may + * send a SIGEMT before tipout has a chance to set up catching + * it; so wait a second, then setscript() + */ + if (boolean(value(SCRIPT))) { + sleep(1); + setscript(); + } + + while (1) { + gch = getchar()&0177; + if ((gch == character(value(ESCAPE))) && bol) { + if (!(gch = escape())) + continue; + } else if (!cumode && gch == character(value(RAISECHAR))) { + boolean(value(RAISE)) = !boolean(value(RAISE)); + continue; + } else if (gch == '\r') { + bol = 1; + pwrite(FD, &gch, 1); + if (boolean(value(HALFDUPLEX))) + printf("\r\n"); + continue; + } else if (!cumode && gch == character(value(FORCE))) + gch = getchar()&0177; + bol = any(gch, value(EOL)); + if (boolean(value(RAISE)) && islower(gch)) + gch = toupper(gch); + pwrite(FD, &gch, 1); + if (boolean(value(HALFDUPLEX))) + printf("%c", gch); + } +} + +extern esctable_t etable[]; + +/* + * Escape handler -- + * called on recognition of ``escapec'' at the beginning of a line + */ +escape() +{ + register char gch; + register esctable_t *p; + char c = character(value(ESCAPE)); + + gch = (getchar()&0177); + for (p = etable; p->e_char; p++) + if (p->e_char == gch) { + if ((p->e_flags&PRIV) && uid) + continue; + printf("%s", ctrl(c)); + (*p->e_func)(gch); + return (0); + } + /* ESCAPE ESCAPE forces ESCAPE */ + if (c != gch) + pwrite(FD, &c, 1); + return (gch); +} + +speed(n) + int n; +{ + register int *p; + + for (p = bauds; *p != -1; p++) + if (*p == n) + return (p - bauds); + return (NULL); +} + +any(c, p) + register char c, *p; +{ + while (p && *p) + if (*p++ == c) + return (1); + return (0); +} + +size(s) + register char *s; +{ + register int i = 0; + + while (s && *s++) + i++; + return (i); +} + +char * +interp(s) + register char *s; +{ + static char buf[256]; + register char *p = buf, c, *q; + + while (c = *s++) { + for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) + if (*q++ == c) { + *p++ = '\\'; *p++ = *q; + goto next; + } + if (c < 040) { + *p++ = '^'; *p++ = c + 'A'-1; + } else if (c == 0177) { + *p++ = '^'; *p++ = '?'; + } else + *p++ = c; + next: + ; + } + *p = '\0'; + return (buf); +} + +char * +ctrl(c) + char c; +{ + static char s[3]; + + if (c < 040 || c == 0177) { + s[0] = '^'; + s[1] = c == 0177 ? '?' : c+'A'-1; + s[2] = '\0'; + } else { + s[0] = c; + s[1] = '\0'; + } + return (s); +} + +/* + * Help command + */ +help(c) + char c; +{ + register esctable_t *p; + + printf("%c\r\n", c); + for (p = etable; p->e_char; p++) { + if ((p->e_flags&PRIV) && uid) + continue; + printf("%2s", ctrl(character(value(ESCAPE)))); + printf("%-2s %c %s\r\n", ctrl(p->e_char), + p->e_flags&EXP ? '*': ' ', p->e_help); + } +} + +/* + * Set up the "remote" tty's state + */ +ttysetup(speed) + int speed; +{ + unsigned bits = LDECCTQ; + + arg.sg_ispeed = arg.sg_ospeed = speed; + arg.sg_flags = RAW; + if (boolean(value(TAND))) + arg.sg_flags |= TANDEM; + ioctl(FD, TIOCSETP, (char *)&arg); + ioctl(FD, TIOCLBIS, (char *)&bits); +} + +/* + * Return "simple" name from a file name, + * strip leading directories. + */ +char * +sname(s) + register char *s; +{ + register char *p = s; + + while (*s) + if (*s++ == '/') + p = s; + return (p); +} + +static char partab[0200]; +static int bits8; + +/* + * Do a write to the remote machine with the correct parity. + * We are doing 8 bit wide output, so we just generate a character + * with the right parity and output it. + */ +pwrite(fd, buf, n) + int fd; + char *buf; + register int n; +{ + register int i; + register char *bp; + extern int errno; + + bp = buf; + if (bits8 == 0) + for (i = 0; i < n; i++) { + *bp = partab[(*bp) & 0177]; + bp++; + } + if (write(fd, buf, n) < 0) { + if (errno == EIO) + tipabort("Lost carrier."); + /* this is questionable */ + perror("write"); + } +} + +/* + * Build a parity table with appropriate high-order bit. + */ +setparity(defparity) + char *defparity; +{ + register int i, flip, clr, set; + char *parity; + extern char evenpartab[]; + + if (value(PARITY) == NOSTR) + value(PARITY) = defparity; + parity = value(PARITY); + if (equal(parity, "none")) { + bits8 = 1; + return; + } + bits8 = 0; + flip = 0; + clr = 0377; + set = 0; + if (equal(parity, "odd")) + flip = 0200; /* reverse bit 7 */ + else if (equal(parity, "zero")) + clr = 0177; /* turn off bit 7 */ + else if (equal(parity, "one")) + set = 0200; /* turn on bit 7 */ + else if (!equal(parity, "even")) { + (void) fprintf(stderr, "%s: unknown parity value\r\n", parity); + (void) fflush(stderr); + } + for (i = 0; i < 0200; i++) + partab[i] = evenpartab[i] ^ flip | set & clr; +} diff --git a/usr.bin/tip/tip.h b/usr.bin/tip/tip.h new file mode 100644 index 0000000..403e17f --- /dev/null +++ b/usr.bin/tip/tip.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)tip.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * tip - terminal interface program + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Remote host attributes + */ +char *DV; /* UNIX device(s) to open */ +char *EL; /* chars marking an EOL */ +char *CM; /* initial connection message */ +char *IE; /* EOT to expect on input */ +char *OE; /* EOT to send to complete FT */ +char *CU; /* call unit if making a phone call */ +char *AT; /* acu type */ +char *PN; /* phone number(s) */ +char *DI; /* disconnect string */ +char *PA; /* parity to be generated */ + +char *PH; /* phone number file */ +char *RM; /* remote file name */ +char *HO; /* host name */ + +long BR; /* line speed for conversation */ +long FS; /* frame size for transfers */ + +char DU; /* this host is dialed up */ +char HW; /* this device is hardwired, see hunt.c */ +char *ES; /* escape character */ +char *EX; /* exceptions */ +char *FO; /* force (literal next) char*/ +char *RC; /* raise character */ +char *RE; /* script record file */ +char *PR; /* remote prompt */ +long DL; /* line delay for file transfers to remote */ +long CL; /* char delay for file transfers to remote */ +long ET; /* echocheck timeout */ +char HD; /* this host is half duplex - do local echo */ + +/* + * String value table + */ +typedef + struct { + char *v_name; /* whose name is it */ + char v_type; /* for interpreting set's */ + char v_access; /* protection of touchy ones */ + char *v_abrev; /* possible abreviation */ + char *v_value; /* casted to a union later */ + } + value_t; + +#define STRING 01 /* string valued */ +#define BOOL 02 /* true-false value */ +#define NUMBER 04 /* numeric value */ +#define CHAR 010 /* character value */ + +#define WRITE 01 /* write access to variable */ +#define READ 02 /* read access */ + +#define CHANGED 01 /* low bit is used to show modification */ +#define PUBLIC 1 /* public access rights */ +#define PRIVATE 03 /* private to definer */ +#define ROOT 05 /* root defined */ + +#define TRUE 1 +#define FALSE 0 + +#define ENVIRON 020 /* initialize out of the environment */ +#define IREMOTE 040 /* initialize out of remote structure */ +#define INIT 0100 /* static data space used for initialization */ +#define TMASK 017 + +/* + * Definition of ACU line description + */ +typedef + struct { + char *acu_name; + int (*acu_dialer)(); + int (*acu_disconnect)(); + int (*acu_abort)(); + } + acu_t; + +#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */ + +/* + * variable manipulation stuff -- + * if we defined the value entry in value_t, then we couldn't + * initialize it in vars.c, so we cast it as needed to keep lint + * happy. + */ +typedef + union { + int zz_number; + short zz_boolean[2]; + char zz_character[4]; + int *zz_address; + } + zzhack; + +#define value(v) vtable[v].v_value + +#define number(v) ((((zzhack *)(&(v))))->zz_number) + +#if BYTE_ORDER == LITTLE_ENDIAN +#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean[0]) +#define character(v) ((((zzhack *)(&(v))))->zz_character[0]) +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define boolean(v) ((((zzhack *)(&(v))))->zz_boolean[1]) +#define character(v) ((((zzhack *)(&(v))))->zz_character[3]) +#endif + +#define address(v) ((((zzhack *)(&(v))))->zz_address) + +/* + * Escape command table definitions -- + * lookup in this table is performed when ``escapec'' is recognized + * at the begining of a line (as defined by the eolmarks variable). +*/ + +typedef + struct { + char e_char; /* char to match on */ + char e_flags; /* experimental, priviledged */ + char *e_help; /* help string */ + int (*e_func)(); /* command */ + } + esctable_t; + +#define NORM 00 /* normal protection, execute anyone */ +#define EXP 01 /* experimental, mark it with a `*' on help */ +#define PRIV 02 /* priviledged, root execute only */ + +extern int vflag; /* verbose during reading of .tiprc file */ +extern value_t vtable[]; /* variable table */ + +#ifndef ACULOG +#define logent(a, b, c, d) +#define loginit() +#endif + +/* + * Definition of indices into variable table so + * value(DEFINE) turns into a static address. + */ + +#define BEAUTIFY 0 +#define BAUDRATE 1 +#define DIALTIMEOUT 2 +#define EOFREAD 3 +#define EOFWRITE 4 +#define EOL 5 +#define ESCAPE 6 +#define EXCEPTIONS 7 +#define FORCE 8 +#define FRAMESIZE 9 +#define HOST 10 +#define LOG 11 +#define PHONES 12 +#define PROMPT 13 +#define RAISE 14 +#define RAISECHAR 15 +#define RECORD 16 +#define REMOTE 17 +#define SCRIPT 18 +#define TABEXPAND 19 +#define VERBOSE 20 +#define SHELL 21 +#define HOME 22 +#define ECHOCHECK 23 +#define DISCONNECT 24 +#define TAND 25 +#define LDELAY 26 +#define CDELAY 27 +#define ETIMEOUT 28 +#define RAWFTP 29 +#define HALFDUPLEX 30 +#define LECHO 31 +#define PARITY 32 + +#define NOVAL ((value_t *)NULL) +#define NOACU ((acu_t *)NULL) +#define NOSTR ((char *)NULL) +#define NOFILE ((FILE *)NULL) +#define NOPWD ((struct passwd *)0) + +struct sgttyb arg; /* current mode of local terminal */ +struct sgttyb defarg; /* initial mode of local terminal */ +struct tchars tchars; /* current state of terminal */ +struct tchars defchars; /* initial state of terminal */ +struct ltchars ltchars; /* current local characters of terminal */ +struct ltchars deflchars; /* initial local characters of terminal */ + +FILE *fscript; /* FILE for scripting */ + +int fildes[2]; /* file transfer synchronization channel */ +int repdes[2]; /* read process sychronization channel */ +int FD; /* open file descriptor to remote host */ +int AC; /* open file descriptor to dialer (v831 only) */ +int vflag; /* print .tiprc initialization sequence */ +int sfd; /* for ~< operation */ +int pid; /* pid of tipout */ +uid_t uid, euid; /* real and effective user id's */ +gid_t gid, egid; /* real and effective group id's */ +int stop; /* stop transfer session flag */ +int quit; /* same; but on other end */ +int intflag; /* recognized interrupt */ +int stoprompt; /* for interrupting a prompt session */ +int timedout; /* ~> transfer timedout */ +int cumode; /* simulating the "cu" program */ + +char fname[80]; /* file name buffer for ~< */ +char copyname[80]; /* file name buffer for ~> */ +char ccc; /* synchronization character */ +char ch; /* for tipout */ +char *uucplock; /* name of lock file for uucp's */ + +int odisc; /* initial tty line discipline */ +extern int disc; /* current tty discpline */ + +extern char *ctrl(); +extern char *vinterp(); +extern char *connect(); diff --git a/usr.bin/tip/tipout.c b/usr.bin/tip/tipout.c new file mode 100644 index 0000000..7288eb8 --- /dev/null +++ b/usr.bin/tip/tipout.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)tipout.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" +/* + * tip + * + * lower fork of tip -- handles passive side + * reading from the remote host + */ + +static jmp_buf sigbuf; + +/* + * TIPOUT wait state routine -- + * sent by TIPIN when it wants to posses the remote host + */ +void +intIOT() +{ + + write(repdes[1],&ccc,1); + read(fildes[0], &ccc,1); + longjmp(sigbuf, 1); +} + +/* + * Scripting command interpreter -- + * accepts script file name over the pipe and acts accordingly + */ +void +intEMT() +{ + char c, line[256]; + register char *pline = line; + char reply; + + read(fildes[0], &c, 1); + while (c != '\n') { + *pline++ = c; + read(fildes[0], &c, 1); + } + *pline = '\0'; + if (boolean(value(SCRIPT)) && fscript != NULL) + fclose(fscript); + if (pline == line) { + boolean(value(SCRIPT)) = FALSE; + reply = 'y'; + } else { + if ((fscript = fopen(line, "a")) == NULL) + reply = 'n'; + else { + reply = 'y'; + boolean(value(SCRIPT)) = TRUE; + } + } + write(repdes[1], &reply, 1); + longjmp(sigbuf, 1); +} + +void +intTERM() +{ + + if (boolean(value(SCRIPT)) && fscript != NULL) + fclose(fscript); + exit(0); +} + +void +intSYS() +{ + + boolean(value(BEAUTIFY)) = !boolean(value(BEAUTIFY)); + longjmp(sigbuf, 1); +} + +/* + * ****TIPOUT TIPOUT**** + */ +tipout() +{ + char buf[BUFSIZ]; + register char *cp; + register int cnt; + extern int errno; + int omask; + + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGEMT, intEMT); /* attention from TIPIN */ + signal(SIGTERM, intTERM); /* time to go signal */ + signal(SIGIOT, intIOT); /* scripting going on signal */ + signal(SIGHUP, intTERM); /* for dial-ups */ + signal(SIGSYS, intSYS); /* beautify toggle */ + (void) setjmp(sigbuf); + for (omask = 0;; sigsetmask(omask)) { + cnt = read(FD, buf, BUFSIZ); + if (cnt <= 0) { + /* lost carrier */ + if (cnt < 0 && errno == EIO) { + sigblock(sigmask(SIGTERM)); + intTERM(); + /*NOTREACHED*/ + } + continue; + } +#define ALLSIGS sigmask(SIGEMT)|sigmask(SIGTERM)|sigmask(SIGIOT)|sigmask(SIGSYS) + omask = sigblock(ALLSIGS); + for (cp = buf; cp < buf + cnt; cp++) + *cp &= 0177; + write(1, buf, cnt); + if (boolean(value(SCRIPT)) && fscript != NULL) { + if (!boolean(value(BEAUTIFY))) { + fwrite(buf, 1, cnt, fscript); + continue; + } + for (cp = buf; cp < buf + cnt; cp++) + if ((*cp >= ' ' && *cp <= '~') || + any(*cp, value(EXCEPTIONS))) + putc(*cp, fscript); + } + } +} diff --git a/usr.bin/tip/uucplock.c b/usr.bin/tip/uucplock.c new file mode 100644 index 0000000..6761857 --- /dev/null +++ b/usr.bin/tip/uucplock.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1988, 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[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "pathnames.h" + +/* + * uucp style locking routines + * return: 0 - success + * -1 - failure + */ + +uu_lock(ttyname) + char *ttyname; +{ + extern int errno; + int fd, pid; + char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN]; + off_t lseek(); + + (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname); + fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0660); + if (fd < 0) { + /* + * file is already locked + * check to see if the process holding the lock still exists + */ + fd = open(tbuf, O_RDWR, 0); + if (fd < 0) { + perror("lock open"); + return(-1); + } + if (read(fd, &pid, sizeof(pid)) != sizeof(pid)) { + (void)close(fd); + perror("lock read"); + return(-1); + } + + if (kill(pid, 0) == 0 || errno != ESRCH) { + (void)close(fd); /* process is still running */ + return(-1); + } + /* + * The process that locked the file isn't running, so + * we'll lock it ourselves + */ + if (lseek(fd, 0L, L_SET) < 0) { + (void)close(fd); + perror("lock lseek"); + return(-1); + } + /* fall out and finish the locking process */ + } + pid = getpid(); + if (write(fd, (char *)&pid, sizeof(pid)) != sizeof(pid)) { + (void)close(fd); + (void)unlink(tbuf); + perror("lock write"); + return(-1); + } + (void)close(fd); + return(0); +} + +uu_unlock(ttyname) + char *ttyname; +{ + char tbuf[sizeof(_PATH_LOCKDIRNAME) + MAXNAMLEN]; + + (void)sprintf(tbuf, _PATH_LOCKDIRNAME, ttyname); + return(unlink(tbuf)); +} diff --git a/usr.bin/tip/value.c b/usr.bin/tip/value.c new file mode 100644 index 0000000..ce29a21 --- /dev/null +++ b/usr.bin/tip/value.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)value.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" + +#define MIDDLE 35 + +static value_t *vlookup(); +static int col = 0; + +/* + * Variable manipulation + */ +vinit() +{ + register value_t *p; + register char *cp; + FILE *f; + char file[256]; + + for (p = vtable; p->v_name != NULL; p++) { + if (p->v_type&ENVIRON) + if (cp = getenv(p->v_name)) + p->v_value = cp; + if (p->v_type&IREMOTE) + number(p->v_value) = *address(p->v_value); + } + /* + * Read the .tiprc file in the HOME directory + * for sets + */ + strcpy(file, value(HOME)); + strcat(file, "/.tiprc"); + if ((f = fopen(file, "r")) != NULL) { + register char *tp; + + while (fgets(file, sizeof(file)-1, f) != NULL) { + if (vflag) + printf("set %s", file); + if (tp = rindex(file, '\n')) + *tp = '\0'; + vlex(file); + } + fclose(f); + } + /* + * To allow definition of exception prior to fork + */ + vtable[EXCEPTIONS].v_access &= ~(WRITE<v_access, WRITE)) { + printf("access denied\r\n"); + return; + } + switch (p->v_type&TMASK) { + + case STRING: + if (p->v_value && equal(p->v_value, v)) + return; + if (!(p->v_type&(ENVIRON|INIT))) + free(p->v_value); + if ((p->v_value = malloc(size(v)+1)) == NOSTR) { + printf("out of core\r\n"); + return; + } + p->v_type &= ~(ENVIRON|INIT); + strcpy(p->v_value, v); + break; + + case NUMBER: + if (number(p->v_value) == number(v)) + return; + number(p->v_value) = number(v); + break; + + case BOOL: + if (boolean(p->v_value) == (*v != '!')) + return; + boolean(p->v_value) = (*v != '!'); + break; + + case CHAR: + if (character(p->v_value) == *v) + return; + character(p->v_value) = *v; + } + p->v_access |= CHANGED; +} + +static void vprint(); + +vlex(s) + register char *s; +{ + register value_t *p; + static void vtoken(); + + if (equal(s, "all")) { + for (p = vtable; p->v_name; p++) + if (vaccess(p->v_access, READ)) + vprint(p); + } else { + register char *cp; + + do { + if (cp = vinterp(s, ' ')) + cp++; + vtoken(s); + s = cp; + } while (s); + } + if (col > 0) { + printf("\r\n"); + col = 0; + } +} + +static void +vtoken(s) + register char *s; +{ + register value_t *p; + register char *cp; + char *expand(); + + if (cp = index(s, '=')) { + *cp = '\0'; + if (p = vlookup(s)) { + cp++; + if (p->v_type&NUMBER) + vassign(p, atoi(cp)); + else { + if (strcmp(s, "record") == 0) + cp = expand(cp); + vassign(p, cp); + } + return; + } + } else if (cp = index(s, '?')) { + *cp = '\0'; + if ((p = vlookup(s)) && vaccess(p->v_access, READ)) { + vprint(p); + return; + } + } else { + if (*s != '!') + p = vlookup(s); + else + p = vlookup(s+1); + if (p != NOVAL) { + vassign(p, s); + return; + } + } + printf("%s: unknown variable\r\n", s); +} + +static void +vprint(p) + register value_t *p; +{ + register char *cp; + extern char *interp(), *ctrl(); + + if (col > 0 && col < MIDDLE) + while (col++ < MIDDLE) + putchar(' '); + col += size(p->v_name); + switch (p->v_type&TMASK) { + + case BOOL: + if (boolean(p->v_value) == FALSE) { + col++; + putchar('!'); + } + printf("%s", p->v_name); + break; + + case STRING: + printf("%s=", p->v_name); + col++; + if (p->v_value) { + cp = interp(p->v_value, NULL); + col += size(cp); + printf("%s", cp); + } + break; + + case NUMBER: + col += 6; + printf("%s=%-5d", p->v_name, number(p->v_value)); + break; + + case CHAR: + printf("%s=", p->v_name); + col++; + if (p->v_value) { + cp = ctrl(character(p->v_value)); + col += size(cp); + printf("%s", cp); + } + break; + } + if (col >= MIDDLE) { + col = 0; + printf("\r\n"); + return; + } +} + + +static int +vaccess(mode, rw) + register unsigned mode, rw; +{ + if (mode & (rw<v_name; p++) + if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s))) + return (p); + return (NULL); +} + +char * +vinterp(s, stop) + register char *s; + char stop; +{ + register char *p = s, c; + int num; + + while ((c = *s++) && c != stop) + switch (c) { + + case '^': + if (*s) + *p++ = *s++ - 0100; + else + *p++ = c; + break; + + case '\\': + num = 0; + c = *s++; + if (c >= '0' && c <= '7') + num = (num<<3)+(c-'0'); + else { + register char *q = "n\nr\rt\tb\bf\f"; + + for (; *q; q++) + if (c == *q++) { + *p++ = *q; + goto cont; + } + *p++ = c; + cont: + break; + } + if ((c = *s++) >= '0' && c <= '7') { + num = (num<<3)+(c-'0'); + if ((c = *s++) >= '0' && c <= '7') + num = (num<<3)+(c-'0'); + else + s--; + } else + s--; + *p++ = num; + break; + + default: + *p++ = c; + } + *p = '\0'; + return (c == stop ? s-1 : NULL); +} + +/* + * assign variable s with value v (for NUMBER or STRING or CHAR types) + */ + +vstring(s,v) + register char *s; + register char *v; +{ + register value_t *p; + char *expand(); + + p = vlookup(s); + if (p == 0) + return (1); + if (p->v_type&NUMBER) + vassign(p, atoi(v)); + else { + if (strcmp(s, "record") == 0) + v = expand(v); + vassign(p, v); + } + return (0); +} diff --git a/usr.bin/tip/vars.c b/usr.bin/tip/vars.c new file mode 100644 index 0000000..debe01b --- /dev/null +++ b/usr.bin/tip/vars.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1983, 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[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tip.h" +#include "pathnames.h" + +/* + * Definition of variables + */ +value_t vtable[] = { + { "beautify", BOOL, (READ|WRITE)< diff --git a/usr.bin/tn3270/Makefile.inc b/usr.bin/tn3270/Makefile.inc new file mode 100644 index 0000000..bd2446e --- /dev/null +++ b/usr.bin/tn3270/Makefile.inc @@ -0,0 +1,4 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/6/93 + +KBD= unix.kbd +CFLAGS+=-DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO -DTN3270 diff --git a/usr.bin/tn3270/api/api_bsd.c b/usr.bin/tn3270/api/api_bsd.c new file mode 100644 index 0000000..46db372 --- /dev/null +++ b/usr.bin/tn3270/api/api_bsd.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)api_bsd.c 8.2 (Berkeley) 1/7/94"; +#endif /* not lint */ + +#if defined(unix) + +#include +#include +#include +#include +#include + +#include "../ctlr/api.h" +#include "api_exch.h" + + +int +api_close_api() +{ + if (api_exch_outcommand(EXCH_CMD_DISASSOCIATE) == -1) { + return -1; + } else if (api_exch_flush() == -1) { + return -1; + } else { + return 0; + } +} + + +int +api_open_api(string) +char *string; /* if non-zero, where to connect to */ +{ + struct sockaddr_in server; + struct hostent *hp; + struct storage_descriptor sd; + extern char *getenv(); + char thehostname[100]; + char keyname[100]; + char inkey[100]; + FILE *keyfile; + int sock; + unsigned int port; + int i; + + if (string == 0) { + string = getenv("API3270"); /* Get API */ + if (string == 0) { + fprintf(stderr, + "API3270 environmental variable not set - no API.\n"); + return -1; /* Nothing */ + } + } + + if (sscanf(string, "%[^:]:%d:%s", thehostname, + (int *)&port, keyname) != 3) { + fprintf(stderr, "API3270 environmental variable has bad format.\n"); + return -1; + } + /* Now, try to connect */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("opening API socket"); + return -1; + } + server.sin_family = AF_INET; + hp = gethostbyname(thehostname); + if (hp == 0) { + fprintf(stderr, "%s specifies bad host name.\n", string); + return -1; + } + bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); + server.sin_port = htons(port); + + if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0) { + perror("connecting to API server"); + return -1; + } + /* Now, try application level connection */ + if (api_exch_init(sock, "client") == -1) { + return -1; + } + if (api_exch_outcommand(EXCH_CMD_ASSOCIATE) == -1) { + return -1; + } + keyfile = fopen(keyname, "r"); + if (keyfile == 0) { + perror("fopen"); + return -1; + } + if (fscanf(keyfile, "%s\n", inkey) != 1) { + perror("fscanf"); + return -1; + } + sd.length = strlen(inkey)+1; + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, sd.length, inkey) == -1) { + return -1; + } + while ((i = api_exch_nextcommand()) != EXCH_CMD_ASSOCIATED) { + int passwd_length; + char *passwd, *getpass(); + char buffer[200]; + + switch (i) { + case EXCH_CMD_REJECTED: + if (api_exch_intype(EXCH_TYPE_STORE_DESC, + sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { + return -1; + } + buffer[sd.length] = 0; + fprintf(stderr, "%s\n", buffer); + if (api_exch_outcommand(EXCH_CMD_ASSOCIATE) == -1) { + return -1; + } + break; + case EXCH_CMD_SEND_AUTH: + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { + return -1; + } + buffer[sd.length] = 0; + passwd = getpass(buffer); /* Go to terminal */ + passwd_length = strlen(passwd); + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { + return -1; + } + buffer[sd.length] = 0; + if (sd.length) { + char *ptr; + + ptr = passwd; + i = 0; + while (*ptr) { + *ptr++ ^= buffer[i++]; + if (i >= sd.length) { + i = 0; + } + } + } + sd.length = passwd_length; + if (api_exch_outcommand(EXCH_CMD_AUTH) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, passwd_length, passwd) == -1) { + return -1; + } + break; + case -1: + return -1; + default: + fprintf(stderr, + "Waiting for connection indicator, received 0x%x.\n", i); + break; + } + } + /* YEAH */ + return 0; /* Happiness! */ +} + + +api_exch_api(regs, sregs, parms, length) +union REGS *regs; +struct SREGS *sregs; +char *parms; +int length; +{ + struct storage_descriptor sd; + int i; + + if (api_exch_outcommand(EXCH_CMD_REQUEST) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_REGS, sizeof *regs, (char *)regs) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof *sregs, (char *)sregs) == -1) { + return -1; + } + sd.length = length; + sd.location = (long) parms; + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, length, parms) == -1) { + return -1; + } + while ((i = api_exch_nextcommand()) != EXCH_CMD_REPLY) { + switch (i) { + case EXCH_CMD_GIMME: + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + /*XXX validity check GIMME? */ + if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, sd.length, + (char *)sd.location) == -1) { + return -1; + } + break; + case EXCH_CMD_HEREIS: + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + /* XXX Validty check HEREIS? */ + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, + (char *)sd.location) == -1) { + return -1; + } + break; + default: + fprintf(stderr, "Waiting for reply command, we got command %d.\n", + i); + return -1; + } + } + if (api_exch_intype(EXCH_TYPE_REGS, sizeof *regs, (char *)regs) == -1) { + return -1; + } + if (api_exch_intype(EXCH_TYPE_SREGS, sizeof *sregs, (char *)sregs) == -1) { + return -1; + } + /* YEAH */ + return 0; /* Happiness! */ +} + +#endif /* unix */ diff --git a/usr.bin/tn3270/api/api_exch.c b/usr.bin/tn3270/api/api_exch.c new file mode 100644 index 0000000..a4626b9 --- /dev/null +++ b/usr.bin/tn3270/api/api_exch.c @@ -0,0 +1,429 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)api_exch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include "../general/general.h" + +#include "api_exch.h" + +static int sock; /* Socket number */ + +static char whoarewe[40] = ""; +#define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); + +static enum {CONTENTION, SEND, RECEIVE } conversation; + +static struct exch_exch exch_state; + +static unsigned int + my_sequence, + your_sequence; + +static char ibuffer[4000], *ibuf_next, *ibuf_last; +#define IBUFADDED(i) ibuf_last += (i) +#define IBUFAVAILABLE() (ibuf_last-ibuf_next) +#define IBUFFER() ibuffer +#define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1) +#define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } +#define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) + +char obuffer[4000], *obuf_next; +#define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } +#define OBUFAVAILABLE() (obuf_next - obuffer) +#define OBUFFER() obuffer +#define OBUFRESET() obuf_next = obuffer +#define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) + + +static int +outflush() +{ + int length = OBUFAVAILABLE(); + + if (length != 0) { + if (write(sock, OBUFFER(), length) != length) { + WHO_ARE_WE(); + perror("write"); + return -1; + } + OBUFRESET(); + } + return 0; /* All OK */ +} + + +static int +iget(location, length) +char *location; +int length; +{ + int count; + + if (OBUFAVAILABLE()) { + if (outflush() == -1) { + return -1; + } + } + if ((count = IBUFAVAILABLE()) != 0) { + if (count > length) { + count = length; + } + IBUFGETBYTES(location, count); + length -= count; + location += count; + } + while (length) { + if (ibuf_next == ibuf_last) { + IBUFRESET(); + } + if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) { + WHO_ARE_WE(); + perror("read"); + return -1; + } + if (count == 0) { + /* Reading past end-of-file */ + WHO_ARE_WE(); + fprintf(stderr, "End of file read\r\n"); + return -1; + } + IBUFADDED(count); + if (count > length) { + count = length; + } + IBUFGETBYTES(location, count); + length -= count; + location += count; + } + return 0; +} + +static char * +exch_to_ascii(exch) +int exch; /* opcode to decode */ +{ + switch (exch) { + case EXCH_EXCH_COMMAND: + return "Command"; + case EXCH_EXCH_TYPE: + return "Type"; + case EXCH_EXCH_TURNAROUND: + return "Turnaround"; + case EXCH_EXCH_RTS: + return "Request to Send"; + default: + { + static char unknown[40]; + + sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); + return unknown; + } + } +} + +/* + * Send the exch structure, updating the sequnce number field. + */ + +static int +send_state() +{ + if (OBUFROOM() < sizeof exch_state) { + if (outflush() == -1) { + return -1; + } + } + my_sequence = (my_sequence+1)&0xff; + exch_state.my_sequence = my_sequence; + exch_state.your_sequence = your_sequence; + OBUFADDBYTES((char *)&exch_state, sizeof exch_state); + return 0; +} + +/* + * Receive the exch structure from the other side, checking + * sequence numbering. + */ + +static int +receive_state() +{ + if (iget((char *)&exch_state, sizeof exch_state) == -1) { + return -1; + } + if (conversation != CONTENTION) { + if (exch_state.your_sequence != my_sequence) { + WHO_ARE_WE(); + fprintf(stderr, "Send sequence number mismatch.\n"); + return -1; + } + if (exch_state.my_sequence != ((++your_sequence)&0xff)) { + WHO_ARE_WE(); + fprintf(stderr, "Receive sequence number mismatch.\n"); + return -1; + } + } + your_sequence = exch_state.my_sequence; + return 0; +} + +static int +enter_receive() +{ + switch (conversation) { + case CONTENTION: + exch_state.opcode = EXCH_EXCH_TURNAROUND; + if (send_state() == -1) { + return -1; + } + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_RTS) { + WHO_ARE_WE(); + fprintf(stderr, "In CONTENTION state: "); + if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { + fprintf(stderr, + "Both sides tried to enter RECEIVE state.\n"); + } else { + fprintf(stderr, + "Protocol error trying to enter RECEIVE state.\n"); + } + return -1; + } + break; + case SEND: + exch_state.opcode = EXCH_EXCH_TURNAROUND; + if (send_state() == -1) { + return -1; + } + break; + } + conversation = RECEIVE; + return 0; +} + +static int +enter_send() +{ + switch (conversation) { + case CONTENTION: + exch_state.opcode = EXCH_EXCH_RTS; + if (send_state() == -1) { + return -1; + } + /* fall through */ + case RECEIVE: + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { + WHO_ARE_WE(); + fprintf(stderr, "Conversation error - both sides in SEND state.\n"); + return -1; + } + } + conversation = SEND; + return 0; +} + +int +api_exch_nextcommand() +{ + if (conversation != RECEIVE) { + if (enter_receive() == -1) { + return -1; + } + } + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_COMMAND) { + WHO_ARE_WE(); + fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", + exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); + return -1; + } + return exch_state.command_or_type; +} + + +int +api_exch_incommand(command) +int command; +{ + int i; + + if ((i = api_exch_nextcommand()) == -1) { + return -1; + } + if (i != command) { + WHO_ARE_WE(); + fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", + command, i); + return -1; + } + return 0; +} + + +int +api_exch_outcommand(command) +int command; +{ + if (conversation != SEND) { + if (enter_send() == -1) { + return -1; + } + } + exch_state.command_or_type = command; + exch_state.opcode = EXCH_EXCH_COMMAND; + if (send_state() == -1) { + return -1; + } else { + return 0; + } +} + + +int +api_exch_outtype(type, length, location) +int + type, + length; +char + *location; +{ + int netleng = length; + + if (conversation != SEND) { + if (enter_send() == -1) { + return -1; + } + } + exch_state.opcode = EXCH_EXCH_TYPE; + exch_state.command_or_type = type; + exch_state.length = netleng; + if (send_state() == -1) { + return -1; + } + if (length) { + if (OBUFROOM() > length) { + OBUFADDBYTES(location, length); + } else { + if (outflush() == -1) { + return -1; + } + if (write(sock, location, length) != length) { + WHO_ARE_WE(); + perror("write"); + return -1; + } + } + } + return 0; +} + + +int +api_exch_intype(type, length, location) +int + type, + length; +char + *location; +{ + int netleng = length; + + if (conversation != RECEIVE) { + if (enter_receive() == -1) { + return -1; + } + } + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_TYPE) { + WHO_ARE_WE(); + fprintf(stderr, + "Expected to receive a %s exchange, received a %s exchange.\n", + exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); + return -1; + } + if (exch_state.command_or_type != type) { + WHO_ARE_WE(); + fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", + type, exch_state.command_or_type); + return -1; + } + if (exch_state.length != netleng) { + fprintf(stderr, "Type 0x%x - expected length %d, received length %u.\n", + type, length, exch_state.length); + return -1; + } + if (iget(location, length) == -1) { + return -1; + } + return 0; +} + +int +api_exch_flush() +{ + return outflush(); +} + +int +api_exch_init(sock_number, ourname) +int sock_number; +char *ourname; +{ + extern char *strcpy(); + + sock = sock_number; + (void) strcpy(whoarewe, ourname); /* For error messages */ + + my_sequence = your_sequence = 0; + + conversation = CONTENTION; /* We don't know which direction */ + + IBUFRESET(); + OBUFRESET(); + + return 0; +} diff --git a/usr.bin/tn3270/api/api_exch.h b/usr.bin/tn3270/api/api_exch.h new file mode 100644 index 0000000..24e6691 --- /dev/null +++ b/usr.bin/tn3270/api/api_exch.h @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)api_exch.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This file describes the structures passed back and forth + * between the API client and API server on a Unix-based + * tn3270 implementation. + */ + +/* + * The following are the low-level opcodes exchanged between the + * two sides. These are designed to allow for type, sequence number, + * and direction checking. + * + * We enforce conversation flow. There are three states: CONTENTION, + * SEND, and RECEIVE. Both sides start in CONTENTION. + * We never leave RECEIVE state without first reading a TURNAROUND + * opcode. We never leave SEND state without first writing a TURNAROUND + * opcode. This scheme ensures that we always have conversation flowing + * in a synchronized direction (or detect an application error), and that + * we never hang with both sides trying to read from the "wire". + * + * State event action + * + * CONTENTION read request send TURNAROUND + * read RTS + * enter RECEIVE + * CONTENTION write request send RTS + * read TURNAROUND + * enter SEND + * + * RECEIVE read request read whatever + * RECEIVE write request read TURNAROUND + * + * SEND read request send TURNAROUND + * SEND write write whatever + */ + +#define EXCH_EXCH_COMMAND 0 /* The following is a command */ +#define EXCH_EXCH_TURNAROUND 1 /* Your turn to send */ +#define EXCH_EXCH_RTS 2 /* Request to send */ +#define EXCH_EXCH_TYPE 3 /* The following is a type */ + +struct exch_exch { + char + opcode; /* COMMAND, TURNAROUND, or TYPE */ + unsigned char + my_sequence, /* 0-ff, initially zero */ + your_sequence, /* 0-ff, initially zero */ + command_or_type; /* Application level command or type */ + unsigned short + length; /* The length of any following data */ +}; + +/* + * The following are the command codes which the higher level protocols + * send and receive. + */ + +#define EXCH_CMD_ASSOCIATE 0 /* Connect [client->server] */ + /* + * struct storage_desc + * char key[] + */ +#define EXCH_CMD_DISASSOCIATE 1 /* Disconnect [client->server] */ +#define EXCH_CMD_SEND_AUTH 2 /* Send password [server->client] */ + /* + * struct storage_desc + * char prompt[] + * struct storage_desc + * char seed[] + */ +#define EXCH_CMD_AUTH 3 /* Authorization [client->server] */ + /* + * struct storage_desc + * char authenticator[] + */ +#define EXCH_CMD_ASSOCIATED 4 /* Connected [server->client] */ +#define EXCH_CMD_REJECTED 5 /* Too bad [server->client] */ + /* + * struct storage_desc + * char message[] + */ + +#define EXCH_CMD_REQUEST 6 /* A request [client->server] */ + /* struct regs, + * struct sregs, + * struct storage_desc + * char bytes[] + */ +#define EXCH_CMD_GIMME 7 /* Send storage [server->client] */ + /* + * struct storage_desc + */ +#define EXCH_CMD_HEREIS 8 /* Here is storage [BOTH WAYS] */ + /* + * struct storage_desc + * char bytes[] + */ +#define EXCH_CMD_REPLY 9 /* End of discussion */ + /* + * struct regs, + * struct sregs, + */ + +/* + * The following are typed parameters sent across the wire. + * + * This should be done much more generally, with some form of + * XDR or mapped conversation ability. + */ + +#define EXCH_TYPE_REGS 0 +#define EXCH_TYPE_SREGS 1 +#define EXCH_TYPE_STORE_DESC 2 +#define EXCH_TYPE_BYTES 3 + +/* + * each parameter that comes over looks like: + * + * char type of following + * short (2 bytes) length of following (network byte order) + * following + */ + +struct storage_descriptor { + long location; /* In network byte order */ + short length; /* In network byte order */ +}; diff --git a/usr.bin/tn3270/api/apilib.c b/usr.bin/tn3270/api/apilib.c new file mode 100644 index 0000000..3146170 --- /dev/null +++ b/usr.bin/tn3270/api/apilib.c @@ -0,0 +1,411 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)apilib.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "../ctlr/api.h" + +#include "apilib.h" + +int + api_sup_errno = 0, /* Supervisor error number */ + api_sup_fcn_id = 0, /* Supervisor function id (0x12) */ + api_fcn_errno = 0, /* Function error number */ + api_fcn_fcn_id = 0; /* Function ID (0x6b, etc.) */ + +static int + gate_sessmgr = 0, + gate_keyboard = 0, + gate_copy = 0, + gate_oiam = 0; + +/* + * Issue an API request, with reg structures supplied by the caller. + * + * Only certain routines need this (supervisor services come to mind). + */ + +static int +api_issue_regs(ah, al, bh, bl, cx, dx, parms, length, regs, sregs) +int ah, al, bh, bl, cx, dx; +char *parms; +int length; +union REGS *regs; +struct SREGS *sregs; +{ + char far *ourseg = parms; + + regs->h.ah = ah; + regs->h.al = al; + regs->h.bh = bh; + regs->h.bl = bl; + regs->x.cx = cx; + regs->x.dx = dx; + sregs->es = FP_SEG(ourseg); + regs->x.di = FP_OFF(ourseg); + +#if defined(MSDOS) + int86x(API_INTERRUPT_NUMBER, regs, regs, sregs); +#endif /* defined(MSDOS) */ +#if defined(unix) + api_exch_api(regs, sregs, parms, length); +#endif /* defined(unix) */ + + if (regs->h.cl != 0) { + api_sup_errno = regs->h.cl; + return -1; + } else { + return 0; + } +} + + +/* + * Issue an API request without requiring caller to supply + * registers. Most routines use this. + */ + +static int +api_issue(ah, al, bh, bl, cx, dx, parms, length) +int + ah, + al, + bh, + bl, + cx, + dx; +char *parms; +int length; /* Length of parms */ +{ + union REGS regs; + struct SREGS sregs; + + return api_issue_regs(ah, al, bh, bl, cx, dx, parms, length, ®s, &sregs); +} + +/* + * Supervisor Services + */ + +int +api_name_resolve(name) +char *name; +{ + NameResolveParms parms; + int i; + union REGS regs; + struct SREGS sregs; + + for (i = 0; i < sizeof parms.gate_name; i++) { + if (*name) { + parms.gate_name[i] = *name++; + } else { + parms.gate_name[i] = ' '; + } + } + + if (api_issue_regs(NAME_RESOLUTION, 0, 0, 0, 0, 0, (char *) &parms, + sizeof parms, ®s, &sregs) == -1) { + return -1; + } else { + return regs.x.dx; + } +} + +#if defined(unix) +/* + * Block until the oia or ps is modified. + */ + +int +api_ps_or_oia_modified() +{ + union REGS regs; + struct SREGS sregs; + + if (api_issue_regs(PS_OR_OIA_MODIFIED, 0, 0, 0, 0, 0, (char *) 0, + 0, ®s, &sregs) == -1) { + return -1; + } else { + return 0; + } +} +#endif /* defined(unix) */ + +/* + * Session Information Services + */ + +api_query_session_id(parms) +QuerySessionIdParms *parms; +{ + if (api_issue(0x09, QUERY_SESSION_ID, 0x80, 0x20, 0, + gate_sessmgr, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + + +api_query_session_parameters(parms) +QuerySessionParametersParms *parms; +{ + if (api_issue(0x09, QUERY_SESSION_PARAMETERS, 0x80, 0x20, 0, + gate_sessmgr, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +api_query_session_cursor(parms) +QuerySessionCursorParms *parms; +{ + if (api_issue(0x09, QUERY_SESSION_CURSOR, 0x80, 0x20, 0xff, + gate_sessmgr, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +/* + * Keyboard Services + */ + +api_connect_to_keyboard(parms) +ConnectToKeyboardParms *parms; +{ + if (api_issue(0x09, CONNECT_TO_KEYBOARD, 0x80, 0x20, 0, + gate_keyboard, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + + +api_disconnect_from_keyboard(parms) +DisconnectFromKeyboardParms *parms; +{ + if (api_issue(0x09, DISCONNECT_FROM_KEYBOARD, 0x80, 0x20, 0, + gate_keyboard, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + + +api_write_keystroke(parms) +WriteKeystrokeParms *parms; +{ + if (api_issue(0x09, WRITE_KEYSTROKE, 0x80, 0x20, 0, + gate_keyboard, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + + +api_disable_input(parms) +DisableInputParms *parms; +{ + if (api_issue(0x09, DISABLE_INPUT, 0x80, 0x20, 0, + gate_keyboard, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +api_enable_input(parms) +EnableInputParms *parms; +{ + if (api_issue(0x09, ENABLE_INPUT, 0x80, 0x20, 0, + gate_keyboard, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +/* + * Copy Services + */ + +api_copy_string(parms) +CopyStringParms *parms; +{ + if (api_issue(0x09, COPY_STRING, 0x80, 0x20, 0xff, + gate_copy, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +/* + * Operator Information Area Services + */ + +api_read_oia_group(parms) +ReadOiaGroupParms *parms; +{ + if (api_issue(0x09, READ_OIA_GROUP, 0x80, 0x20, 0xff, + gate_oiam, (char *)parms, sizeof *parms) == -1) { + api_fcn_errno = 0; + api_fcn_fcn_id = 0; + return -1; + } else if (parms->rc == 0) { + return 0; + } else { + api_fcn_errno = parms->rc; + api_fcn_fcn_id = parms->function_id; + return -1; + } +} + +/* + * The "we are done" routine. This gets called last. + */ + +api_finish() +{ +#if defined(unix) + if (api_close_api() == -1) { + return -1; + } else { + return 0; + } +#endif /* defined(unix) */ +} + + +/* + * The initialization routine. Be sure to call this first. + */ + +api_init() +{ +#if defined(MSDOS) + union REGS regs; + struct SREGS sregs; + + regs.h.ah = 0x35; + regs.h.al = API_INTERRUPT_NUMBER; + intdosx(®s, ®s, &sregs); + + if ((regs.x.bx == 0) && (sregs.es == 0)) { + return 0; /* Interrupt not being handled */ + } +#endif /* defined(MSDOS) */ +#if defined(unix) + if (api_open_api((char *)0) == -1) { + return 0; + } +#endif /* defined(unix) */ + + gate_sessmgr = api_name_resolve("SESSMGR"); + gate_keyboard = api_name_resolve("KEYBOARD"); + gate_copy = api_name_resolve("COPY"); + gate_oiam = api_name_resolve("OIAM"); + + if ((gate_sessmgr == gate_keyboard) || + (gate_sessmgr == gate_copy) || + (gate_sessmgr == gate_oiam) || + (gate_keyboard == gate_copy) || + (gate_keyboard == gate_oiam) || + (gate_copy == gate_oiam)) { + return 0; /* Interrupt doesn't seem correct */ + } + return 1; +} diff --git a/usr.bin/tn3270/api/apilib.h b/usr.bin/tn3270/api/apilib.h new file mode 100644 index 0000000..3253e39 --- /dev/null +++ b/usr.bin/tn3270/api/apilib.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)apilib.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * What one needs to specify + */ + +extern int + api_sup_errno, /* Supervisor error number */ + api_sup_fcn_id, /* Supervisor function id (0x12) */ + api_fcn_errno, /* Function error number */ + api_fcn_fcn_id; /* Function ID (0x6b, etc.) */ diff --git a/usr.bin/tn3270/api/asc_ebc.c b/usr.bin/tn3270/api/asc_ebc.c new file mode 100644 index 0000000..14061f0 --- /dev/null +++ b/usr.bin/tn3270/api/asc_ebc.c @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)asc_ebc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Ascii<->Ebcdic translation tables. + */ + +#include "asc_ebc.h" + +unsigned char asc_ebc[NASCII] = { + +/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 20 */ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, +/* 28 */ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, +/* 30 */ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, +/* 38 */ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, +/* 40 */ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, +/* 48 */ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, +/* 50 */ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, +/* 58 */ 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, +/* 60 */ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, +/* 68 */ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, +/* 70 */ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, +/* 78 */ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x00, + +}; + +/* + * ebcdic to ascii translation tables + */ + +unsigned char ebc_asc[NEBC] = { +/* 00 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 08 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 10 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 18 */ ' ', ' ', ' ', ' ', '*', ' ', ';', ' ', +/* 20 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 28 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 30 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 38 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 40 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + +/* 48 */ ' ', ' ', +#if !defined(MSDOS) + /* 4A */ '\\', +#else /* !defined(MSDOS) */ + /* 4A */ '\233', /* PC cent sign */ +#endif /* !defined(MSDOS) */ + /* 4B */ '.', '<', '(', '+', '|', + +/* 50 */ '&', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* 58 */ ' ', ' ', '!', '$', '*', ')', ';', '^', +/* 60 */ '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', +/* 68 */ ' ', ' ', '|', ',', '%', '_', '>', '?', +/* 70 */ ' ', '^', ' ', ' ', ' ', ' ', ' ', ' ', +/* 78 */ ' ', '`', ':', '#', '@', '\'', '=', '"', +/* 80 */ ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 88 */ 'h', 'i', ' ', ' ', ' ', ' ', ' ', ' ', +/* 90 */ ' ', 'j', 'k', 'l', 'm', 'n', 'o', 'p', +/* 98 */ 'q', 'r', ' ', ' ', ' ', ' ', ' ', ' ', +/* A0 */ ' ', '~', 's', 't', 'u', 'v', 'w', 'x', +/* A8 */ 'y', 'z', ' ', ' ', ' ', '[', ' ', ' ', +/* B0 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', +/* B8 */ ' ', ' ', ' ', ' ', ' ', ']', ' ', ' ', +/* C0 */ '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', +/* C8 */ 'H', 'I', ' ', ' ', ' ', ' ', ' ', ' ', +/* D0 */ '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', +/* D8 */ 'Q', 'R', ' ', ' ', ' ', ' ', ' ', ' ', +/* E0 */ '\\', ' ', 'S', 'T', 'U', 'V', 'W', 'X', +/* E8 */ 'Y', 'Z', ' ', ' ', ' ', ' ', ' ', ' ', +/* F0 */ '0', '1', '2', '3', '4', '5', '6', '7', +/* F8 */ '8', '9', ' ', ' ', ' ', ' ', ' ', ' ', +}; diff --git a/usr.bin/tn3270/api/asc_ebc.h b/usr.bin/tn3270/api/asc_ebc.h new file mode 100644 index 0000000..17c0488 --- /dev/null +++ b/usr.bin/tn3270/api/asc_ebc.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)asc_ebc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Definitions of translate tables used for ascii<->ebcdic translation. + */ + +#define INCLUDED_ASCEBC + +/* + * ascii/ebcdic translation information + */ + +#define NASCII 128 /* number of ascii characters */ + +#define NEBC 256 /* number of ebcdic characters */ + +extern unsigned char + asc_ebc[NASCII], ebc_asc[NEBC]; diff --git a/usr.bin/tn3270/api/astosc.c b/usr.bin/tn3270/api/astosc.c new file mode 100644 index 0000000..ff641d6 --- /dev/null +++ b/usr.bin/tn3270/api/astosc.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)astosc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include "../general/general.h" + +#include "../ctlr/function.h" + +#include "astosc.h" + +struct astosc astosc[256] = { +#include "astosc.out" +}; + +/* compare two strings, ignoring case */ + +static +ustrcmp(string1, string2) +register char *string1; +register char *string2; +{ + register int c1, c2; + + while ((c1 = (unsigned char) *string1++) != 0) { + if (isupper(c1)) { + c1 = tolower(c1); + } + if (isupper(c2 = (unsigned char) *string2++)) { + c2 = tolower(c2); + } + if (c1 < c2) { + return(-1); + } else if (c1 > c2) { + return(1); + } + } + if (*string2) { + return(-1); + } else { + return(0); + } +} + + +/* + * This routine takes a string and returns an integer. It may return + * -1 if there is no other integer which corresponds to the + * string. -1 implies an error. + */ + +int +ascii_to_index(string) +register char *string; +{ + register struct astosc *this; + + for (this = astosc; this <= &astosc[highestof(astosc)]; this++) { + if ((this->name != 0) && (ustrcmp(this->name, string) == 0)) { + return this-astosc; + } + } + return -1; +} diff --git a/usr.bin/tn3270/api/astosc.h b/usr.bin/tn3270/api/astosc.h new file mode 100644 index 0000000..bbafd5f --- /dev/null +++ b/usr.bin/tn3270/api/astosc.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)astosc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This defines the structure used to translate: + * + * ascii name ==> (scancode, shiftstate) + * + * (Actually, map3270 does "ascii name ==> index", and + * termin does "index ==> (scancode, shiftstate)". Both + * mappings use this structure.) + */ + +#define INCLUDED_ASTOSC + +struct astosc { + unsigned char + scancode, /* Scan code for this function */ + shiftstate; /* Shift state for this function */ + enum ctlrfcn function; /* Internal function identifier */ + char *name; /* Name of this function */ +}; + +int ascii_to_index(); /* Function to feed InitControl() */ + +extern struct astosc astosc[256]; diff --git a/usr.bin/tn3270/api/dctype.c b/usr.bin/tn3270/api/dctype.c new file mode 100644 index 0000000..1fd8a90 --- /dev/null +++ b/usr.bin/tn3270/api/dctype.c @@ -0,0 +1,245 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)dctype.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "dctype.h" + +unsigned char dctype[192] = { +/*00*/ + D_SPACE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, +/*10*/ + D_SPACE, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + 0, + 0, + 0, + 0, +/*20*/ + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + D_DIGIT|D_PRINT, + 0, + 0, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, +/*30*/ + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, + 0, + 0, + 0, + 0, + D_PUNCT|D_PRINT, + 0, + D_PUNCT|D_PRINT, + 0, + 0, +/*40*/ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/*50*/ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/*60*/ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/*70*/ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +/*80*/ + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, +/*90*/ + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + D_LOWER|D_PRINT, + 0, + 0, + 0, + 0, + 0, + 0, +/*A0*/ + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, +/*B0*/ + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + D_UPPER|D_PRINT, + 0, + 0, + 0, + 0, + D_PUNCT|D_PRINT, + D_PUNCT|D_PRINT, +}; diff --git a/usr.bin/tn3270/api/dctype.h b/usr.bin/tn3270/api/dctype.h new file mode 100644 index 0000000..2b0c068 --- /dev/null +++ b/usr.bin/tn3270/api/dctype.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)dctype.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_ECTYPE + +#define D_UPPER 0x01 +#define D_LOWER 0x02 +#define D_DIGIT 0x04 +#define D_SPACE 0x08 +#define D_PUNCT 0x10 +#define D_PRINT 0x20 + +#define Disalpha(c) (dctype[(c)]&(D_UPPER|D_LOWER)) +#define Disupper(c) (dctype[(c)]&D_UPPER) +#define Dislower(c) (dctype[(c)]&D_LOWER) +#define Disdigit(c) (dctype[(c)]&D_DIGIT) +#define Disalnum(c) (dctype[(c)]&(D_UPPER|D_LOWER|D_DIGIT)) +#define Disspace(c) (dctype[(c)]&D_SPACE) /* blank or null */ +#define Dispunct(c) (dctype[(c)]&D_PUNCT) +#define Disprint(c) (dctype[(c)]&D_PRINT) + +extern unsigned char dctype[192]; diff --git a/usr.bin/tn3270/api/disp_asc.c b/usr.bin/tn3270/api/disp_asc.c new file mode 100644 index 0000000..85ba106 --- /dev/null +++ b/usr.bin/tn3270/api/disp_asc.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)disp_asc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * There isn't much excuse for this file, but here it is. + */ + +#include "disp_asc.h" + +#include "asc_disp.out" +#include "disp_asc.out" diff --git a/usr.bin/tn3270/api/disp_asc.h b/usr.bin/tn3270/api/disp_asc.h new file mode 100644 index 0000000..5abe92b --- /dev/null +++ b/usr.bin/tn3270/api/disp_asc.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)disp_asc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Define the translate tables used to go between 3270 display code + * and ascii + */ + +extern unsigned char + disp_asc[256], /* Goes between display code and ascii */ + asc_disp[256]; /* Goes between ascii and display code */ diff --git a/usr.bin/tn3270/api/ebc_disp.c b/usr.bin/tn3270/api/ebc_disp.c new file mode 100644 index 0000000..a601099 --- /dev/null +++ b/usr.bin/tn3270/api/ebc_disp.c @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)ebc_disp.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Translate table to map EBCDIC into 3270 display codes. + */ + +unsigned char ebc_disp[256] = { +/*00*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*08*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*10*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*18*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*20*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*28*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*30*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*38*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*40*/ 0x10, 0x0a, 0x0b, 0x1c, 0x1d, 0x1e, 0x1f, 0x2a, +/*48*/ 0x2b, 0x37, 0x1b, 0x32, 0x09, 0x0d, 0x35, 0x16, +/*50*/ 0x30, 0x38, 0x39, 0x3a, 0x3c, 0x3e, 0x3f, 0x40, +/*58*/ 0x41, 0x42, 0x19, 0x1a, 0xbf, 0x0c, 0xbe, 0x36, +/*60*/ 0x31, 0x14, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +/*68*/ 0x49, 0x4a, 0x17, 0x33, 0x2e, 0x2f, 0x08, 0x18, +/*70*/ 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, +/*78*/ 0x53, 0x3d, 0x34, 0x2c, 0x2d, 0x12, 0x11, 0x13, +/*80*/ 0x54, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, +/*88*/ 0x87, 0x88, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, +/*90*/ 0x5b, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, +/*98*/ 0x90, 0x91, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, +/*A0*/ 0x62, 0x3b, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, +/*A8*/ 0x98, 0x99, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, +/*B0*/ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, +/*B8*/ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, +/*C0*/ 0x0f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, +/*C8*/ 0xa7, 0xa8, 0x79, 0x7a, 0x7b, 0x7c, 0x01, 0x02, +/*D0*/ 0x0e, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, +/*D8*/ 0xb0, 0xb1, 0x7d, 0x7e, 0x7f, 0x03, 0x04, 0x05, +/*E0*/ 0x15, 0x9a, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, +/*E8*/ 0xb8, 0xb9, 0x9b, 0x9c, 0x9d, 0x06, 0x07, 0x9e, +/*F0*/ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, +/*F8*/ 0x28, 0x29, 0xba, 0xbb, 0xbc, 0xbd, 0x9f, 0x00, +}; + +/* + * Translate table to map 3270 display codes to EBCDIC. + */ + +unsigned char disp_ebc[192] = { +/*00*/ 0x00, 0xce, 0xcf, 0xdd, 0xde, 0xdf, 0xed, 0xee, +/*08*/ 0x6e, 0x4c, 0x41, 0x42, 0x5d, 0x4d, 0xd0, 0xc0, +/*10*/ 0x40, 0x7e, 0x7d, 0x7f, 0x61, 0xe0, 0x4f, 0x6a, +/*18*/ 0x6f, 0x5a, 0x5b, 0x4a, 0x43, 0x44, 0x45, 0x46, +/*20*/ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, +/*28*/ 0xf8, 0xf9, 0x47, 0x48, 0x7b, 0x7c, 0x6c, 0x6d, +/*30*/ 0x50, 0x60, 0x4b, 0x6b, 0x7a, 0x4e, 0x5f, 0x49, +/*38*/ 0x51, 0x52, 0x53, 0xa1, 0x54, 0x79, 0x55, 0x56, +/*40*/ 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, +/*48*/ 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, +/*50*/ 0x75, 0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, +/*58*/ 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, +/*60*/ 0x9e, 0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, +/*68*/ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, +/*70*/ 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, +/*78*/ 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xda, 0xdb, 0xdc, +/*80*/ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, +/*88*/ 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, +/*90*/ 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, +/*98*/ 0xa8, 0xa9, 0xe1, 0xea, 0xeb, 0xec, 0xef, 0xfe, +/*A0*/ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, +/*A8*/ 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, +/*B0*/ 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, +/*B8*/ 0xe8, 0xe9, 0xfa, 0xfb, 0xfc, 0xfd, 0x5e, 0x5c, +}; diff --git a/usr.bin/tn3270/api/ebc_disp.h b/usr.bin/tn3270/api/ebc_disp.h new file mode 100644 index 0000000..201c39d --- /dev/null +++ b/usr.bin/tn3270/api/ebc_disp.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)ebc_disp.h 8.1 (Berkeley) 6/6/93 + */ + +extern unsigned char + ebc_disp[256], + disp_ebc[192]; diff --git a/usr.bin/tn3270/ascii/default.map b/usr.bin/tn3270/ascii/default.map new file mode 100644 index 0000000..a4cf6e1 --- /dev/null +++ b/usr.bin/tn3270/ascii/default.map @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)default.map 8.1 (Berkeley) 6/6/93 + */ + +/* default.map3270: This file is the system default for the key sequence + * if neither the user's TERM nor "unknown" are found in either of + * MAP3270 or /etc/map3270. + * + * + */ +#if defined(MSDOS) +"tn3270pc{", +" ENTER='^M';CLEAR='^Z'|'^Aw';NL='^N'|'^AO';TAB='^I';DP='^U';FM='^Y';", +" BTAB='^B'|'^[^I'|'^A^O';LEFT='^H'|'^AK';RIGHT='^L'|'^AM';UP='^K'|'^AH';", +" DOWN='^J'|'^AP';HOME='^^'|'^AG';DELETE='^AS'|'^D';EINP='^W';FLINP='^X';", +" EEOF='^E'|'^Au';WERASE='^As';FERASE='^At';INSRT='^[ '|'^AR';CURSEL='^[.';", +" PFK1='^A;'|'^F01'|'^[1'|'^Ax';PFK2='^A<'|'^F02'|'^[2'|'^Ay';SETTAB='^[;';", +" PFK3='^A='|'^F03'|'^[3'|'^Az';CLRTAB='^[+'|'^[:';SETMRG='^[(';", +" PFK4='^A>'|'^F04'|'^[4'|'^A{';PFK5='^A?'|'^F05'|'^[5'|'^A|';", +" PFK6='^A@'|'^F06'|'^[6'|'^A}';PFK7='^AA'|'^AI'|'^F07'|'^[7'|'^A~';", +" PFK8='^AB'|'^AQ'|'^F08'|'^[8'|'^A^?';PFK9='^AC'|'^F09'|'^[9'|'^A^A^@';", +" PFK10='^AD'|'^F10'|'^[0'|'^A^A^A';SETHOM='^[!';COLTAB='^[i'|'^[I';", +" COLBAK='^[b'|'^[B';INDENT='^[l'|'^[L';UNDENT='^[h'|'^[H';", +" PFK11='^AT'|'^F11'|'^[-'|'^A^A^B';PFK12='^AU'|'^F12'|'^A^A^C'|'^[=';", +" PFK13='^AV'|'^F13';PFK14='^AW'|'^F14';PFK15='^AX'|'^F15';", +" PFK16='^AY'|'^F16';", +" PFK17='^AZ'|'^F17';PFK18='^A['|'^F18';PFK19='^A\\\\'|'^F19';", +" PFK20='^A]'|'^F20';PFK21='^A\\^'|'^F21';PFK22='^A_'|'^F22';PA3='^Aj'|'^P3';", +" PFK23='^A`'|'^F23';PFK24='^Aa'|'^F24';PA1='^Ah'|'^P1';PA2='^Ai'|'^P2';", +" RESET='^T'|'^R'; ", +" MASTER_RESET='^G';RESHOW='^V';DELTAB='^[\\\'';ESCAPE='^C';", +"}", +#else /* defined(MSDOS) */ +"generic { clear = '^z'; flinp = '^x'; enter = '^m'; delete = '^d' | '^?';", +" synch = '^r'; reshow = '^v'; eeof = '^e'; tab = '^i';", +" btab = '^b'; nl = '^n'; left = '^h'; right = '^l';", +" up = '^k'; down = '^j'; einp = '^w'; reset = '^t';", +" xoff = '^s'; xon = '^q'; escape = '^c'; ferase = '^u';", +" insrt = '\\E ';", +" pa1 = '^p1'; pa2 = '^p2'; pa3 = '^p3';", +" pfk1 = '\\E1'; pfk2 = '\\E2'; pfk3 = '\\E3'; pfk4 = '\\E4';", +" pfk5 = '\\E5'; pfk6 = '\\E6'; pfk7 = '\\E7'; pfk8 = '\\E8';", +" pfk9 = '\\E9'; pfk10 = '\\E0'; pfk11 = '\\E-'; pfk12 = '\\E=';", +" pfk13 = '\\E!'; pfk14 = '\\E@'; pfk15 = '\\E#'; pfk16 = '\\E$';", +" pfk17 = '\\E%'; pfk18 = '\\E\\^'; pfk19 = '\\E&'; pfk20 = '\\E*';", +" pfk21 = '\\E('; pfk22 = '\\E)'; pfk23 = '\\E_'; pfk24 = '\\E+';", +"}", +#endif /* defined(MSDOS) */ diff --git a/usr.bin/tn3270/ascii/map3270.c b/usr.bin/tn3270/ascii/map3270.c new file mode 100644 index 0000000..0295509 --- /dev/null +++ b/usr.bin/tn3270/ascii/map3270.c @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)map3270.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* This program reads a description file, somewhat like /etc/termcap, + that describes the mapping between the current terminal's keyboard and + a 3270 keyboard. + */ +#ifdef DOCUMENTATION_ONLY +/* here is a sample (very small) entry... + + # this table is sensitive to position on a line. In particular, + # a terminal definition for a terminal is terminated whenever a + # (non-comment) line beginning in column one is found. + # + # this is an entry to map tvi924 to 3270 keys... + v8|tvi924|924|televideo model 924 { + pfk1 = '\E1'; + pfk2 = '\E2'; + clear = '^z'; # clear the screen + } + */ +#endif /* DOCUMENTATION_ONLY */ + +#include +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ + +#define IsPrint(c) ((isprint(c) && !isspace(c)) || ((c) == ' ')) + +#include "state.h" +#include "map3270.h" + +#include "../general/globals.h" + +/* this is the list of types returned by the lex processor */ +#define LEX_CHAR 400 /* plain unadorned character */ +#define LEX_ESCAPED LEX_CHAR+1 /* escaped with \ */ +#define LEX_CARETED LEX_ESCAPED+1 /* escaped with ^ */ +#define LEX_END_OF_FILE LEX_CARETED+1 /* end of file encountered */ +#define LEX_ILLEGAL LEX_END_OF_FILE+1 /* trailing escape character */ + +/* the following is part of our character set dependancy... */ +#define ESCAPE 0x1b +#define TAB 0x09 +#define NEWLINE 0x0a +#define CARRIAGE_RETURN 0x0d + +typedef struct { + int type; /* LEX_* - type of character */ + int value; /* character this was */ +} lexicon; + +typedef struct { + int length; /* length of character string */ + char array[500]; /* character string */ +} stringWithLength; + +#define panic(s) { fprintf(stderr, s); exit(1); } + +static state firstentry = { 0, STATE_NULL, 0, 0 }; +static state *headOfQueue = &firstentry; + +/* the following is a primitive adm3a table, to be used when nothing + * else seems to be avaliable. + */ + +#ifdef DEBUG +static int debug = 0; /* debug flag (for debuggin tables) */ +#endif /* DEBUG */ + +static int (*GetTc)(); +static int doPaste = 1; /* should we have side effects */ +static int picky = 0; /* do we complain of unknown functions? */ +static char usePointer = 0; /* use pointer, or file */ +static FILE *ourFile= 0; +static char *environPointer = 0;/* if non-zero, point to input + * string in core. + */ +static char **whichkey = 0; +static char *keysgeneric[] = { +#include "default.map" /* Define the default default */ + + 0, /* Terminate list of entries */ +}; + ; + +static int Empty = 1, /* is the unget lifo empty? */ + Full = 0; /* is the unget lifo full? */ +static lexicon lifo[200] = { 0 }; /* character stack for parser */ +static int rp = 0, /* read pointer into lifo */ + wp = 0; /* write pointer into lifo */ + +static int +GetC() +{ + int character; + + if (usePointer) { + if ((*environPointer) == 0) { + /* + * If we have reached the end of this string, go on to + * the next (if there is a next). + */ + if (whichkey == 0) { + static char suffix = 'A'; /* From environment */ + char envname[9]; + extern char *getenv(); + + (void) sprintf(envname, "MAP3270%c", suffix++); + environPointer = getenv(envname); + } else { + whichkey++; /* default map */ + environPointer = *whichkey; + } + } + if (*environPointer) { + character = 0xff&*environPointer++; + } else { + character = EOF; + } + } else { + character = getc(ourFile); + } + return(character); +} + +static lexicon +Get() +{ + static lexicon c; + register lexicon *pC = &c; + register int character; + + if (!Empty) { + *pC = lifo[rp]; + rp++; + if (rp == sizeof lifo/sizeof (lexicon)) { + rp = 0; + } + if (rp == wp) { + Empty = 1; + } + Full = 0; + } else { + character = GetC(); + switch (character) { + case EOF: + pC->type = LEX_END_OF_FILE; + break; + case '^': + character = GetC(); + if (!IsPrint(character)) { + pC->type = LEX_ILLEGAL; + } else { + pC->type = LEX_CARETED; + if (character == '?') { + character |= 0x40; /* rubout */ + } else { + character &= 0x1f; + } + } + break; + case '\\': + character = GetC(); + if (!IsPrint(character)) { + pC->type = LEX_ILLEGAL; + } else { + pC->type = LEX_ESCAPED; + switch (character) { + case 'E': case 'e': + character = ESCAPE; + break; + case 't': + character = TAB; + break; + case 'n': + character = NEWLINE; + break; + case 'r': + character = CARRIAGE_RETURN; + break; + default: + pC->type = LEX_ILLEGAL; + break; + } + } + break; + default: + if ((IsPrint(character)) || isspace(character)) { + pC->type = LEX_CHAR; + } else { + pC->type = LEX_ILLEGAL; + } + break; + } + pC->value = character; + } + return(*pC); +} + +static void +UnGet(c) +lexicon c; /* character to unget */ +{ + if (Full) { + fprintf(stderr, "attempt to put too many characters in lifo\n"); + panic("map3270"); + /* NOTREACHED */ + } else { + lifo[wp] = c; + wp++; + if (wp == sizeof lifo/sizeof (lexicon)) { + wp = 0; + } + if (wp == rp) { + Full = 1; + } + Empty = 0; + } +} + +/* + * Construct a control character sequence + * for a special character. + */ +char * +uncontrol(c) + register int c; +{ + static char buf[3]; + + if (c == 0x7f) + return ("^?"); + if (c == '\377') { + return "-1"; + } + if (c >= 0x20) { + buf[0] = c; + buf[1] = 0; + } else { + buf[0] = '^'; + buf[1] = '@'+c; + buf[2] = 0; + } + return (buf); +} + +/* compare two strings, ignoring case */ + +ustrcmp(string1, string2) +register char *string1; +register char *string2; +{ + register int c1, c2; + + while ((c1 = (unsigned char) *string1++) != 0) { + if (isupper(c1)) { + c1 = tolower(c1); + } + if (isupper(c2 = (unsigned char) *string2++)) { + c2 = tolower(c2); + } + if (c1 < c2) { + return(-1); + } else if (c1 > c2) { + return(1); + } + } + if (*string2) { + return(-1); + } else { + return(0); + } +} + + +static stringWithLength * +GetQuotedString() +{ + lexicon lex, *lp; + static stringWithLength output = { 0 }; /* where return value is held */ + char *pointer = output.array; + + lex = Get(); + if ((lex.type != LEX_CHAR) || (lex.value != '\'')) { + UnGet(lex); + return(0); + } + while (1) { + lex = Get(); + if ((lex.type == LEX_CHAR) && (lex.value == '\'')) { + break; + } + lp = &lex; + if ((lp->type == LEX_CHAR) && !IsPrint(lp->value)) { + UnGet(lex); + return(0); /* illegal character in quoted string */ + } + if (pointer >= output.array+sizeof output.array) { + return(0); /* too long */ + } + *pointer++ = lex.value; + } + output.length = pointer-output.array; + return(&output); +} + +#ifdef NOTUSED +static stringWithLength * +GetCharString() +{ + lexicon lex; + static stringWithLength output; + char *pointer = output.array; + + lex = Get(); + + while ((lex.type == LEX_CHAR) && + !isspace(lex.value) && (lex.value != '=')) { + *pointer++ = lex.value; + lex = Get(); + if (pointer >= output.array + sizeof output.array) { + return(0); /* too long */ + } + } + UnGet(lex); + output.length = pointer-output.array; + return(&output); +} +#endif /* NOTUSED */ + +static +GetCharacter(character) +int character; /* desired character */ +{ + lexicon lex; + + lex = Get(); + + if ((lex.type != LEX_CHAR) || (lex.value != character)) { + UnGet(lex); + return(0); + } + return(1); +} + +#ifdef NOTUSED +static +GetString(string) +char *string; /* string to get */ +{ + lexicon lex; + + while (*string) { + lex = Get(); + if ((lex.type != LEX_CHAR) || (lex.value != *string&0xff)) { + UnGet(lex); + return(0); /* XXX restore to state on entry */ + } + string++; + } + return(1); +} +#endif /* NOTUSED */ + + +static stringWithLength * +GetAlphaMericString() +{ + lexicon lex, *lp; + static stringWithLength output = { 0 }; + char *pointer = output.array; +# define IsAlnum(c) (isalnum(c) || (c == '_') \ + || (c == '-') || (c == '.')) + + lex = Get(); + lp = &lex; + + if ((lp->type != LEX_CHAR) || !IsAlnum(lp->value)) { + UnGet(lex); + return(0); + } + + while ((lp->type == LEX_CHAR) && IsAlnum(lp->value)) { + *pointer++ = lex.value; + lex = Get(); + } + UnGet(lex); + *pointer = 0; + output.length = pointer-output.array; + return(&output); +} + + +/* eat up characters until a new line, or end of file. returns terminating + character. + */ + +static lexicon +EatToNL() +{ + lexicon lex; + + lex = Get(); + + while (!((lex.type != LEX_ESCAPED) && (lex.type != LEX_CARETED) && + (lex.value == '\n')) && (!(lex.type == LEX_END_OF_FILE))) { + lex = Get(); + } + if (lex.type != LEX_END_OF_FILE) { + return(Get()); + } else { + return(lex); + } +} + + +static void +GetWS() +{ + lexicon lex, *lp; + + lex = Get(); + lp = &lex; + + while ((lp->type == LEX_CHAR) && + (isspace(lp->value) || (lp->value == '#'))) { + if (lex.value == '#') { + lex = EatToNL(); + } else { + lex = Get(); + } + } + UnGet(lex); +} + +static void +FreeState(pState) +state *pState; +{ + extern int free(); + + free((char *)pState); +} + + +static state * +GetState() +{ + state *pState; + extern char *malloc(); + + pState = (state *) malloc(sizeof (state)); + + pState->result = STATE_NULL; + pState->next = 0; + + return(pState); +} + + +static state * +FindMatchAtThisLevel(pState, character) +state *pState; +int character; +{ + while (pState) { + if (pState->match == character) { + return(pState); + } + pState = pState->next; + } + return(0); +} + + +static state * +PasteEntry(head, string, count, identifier) +state *head; /* points to who should point here... */ +char *string; /* which characters to paste */ +int count; /* number of character to do */ +char *identifier; /* for error messages */ +{ + state *pState, *other; + + if (!doPaste) { /* flag to not have any side effects */ + return((state *)1); + } + if (!count) { + return(head); /* return pointer to the parent */ + } + if ((head->result != STATE_NULL) && (head->result != STATE_GOTO)) { + /* this means that a previously defined sequence is an initial + * part of this one. + */ + fprintf(stderr, "Conflicting entries found when scanning %s\n", + identifier); + return(0); + } +# ifdef DEBUG + if (debug) { + fprintf(stderr, "%s", uncontrol(*string)); + } +# endif /* DEBUG */ + pState = GetState(); + pState->match = *string; + if (head->result == STATE_NULL) { + head->result = STATE_GOTO; + head->address = pState; + other = pState; + } else { /* search for same character */ + if ((other = FindMatchAtThisLevel(head->address, *string)) != 0) { + FreeState(pState); + } else { + pState->next = head->address; + head->address = pState; + other = pState; + } + } + return(PasteEntry(other, string+1, count-1, identifier)); +} + +static +GetInput(tc, identifier) +int tc; +char *identifier; /* entry being parsed (for error messages) */ +{ + stringWithLength *outputString; + state *head; + state fakeQueue; + + if (doPaste) { + head = headOfQueue; /* always points to level above this one */ + } else { + head = &fakeQueue; /* don't have any side effects... */ + } + + if ((outputString = GetQuotedString()) == 0) { + return(0); + } else if (IsPrint(outputString->array[0])) { + fprintf(stderr, + "first character of sequence for %s is not a control type character\n", + identifier); + return(0); + } else { + if ((head = PasteEntry(head, outputString->array, + outputString->length, identifier)) == 0) { + return(0); + } + GetWS(); + while ((outputString = GetQuotedString()) != 0) { + if ((head = PasteEntry(head, outputString->array, + outputString->length, identifier)) == 0) { + return(0); + } + GetWS(); + } + } + if (!doPaste) { + return(1); + } + if ((head->result != STATE_NULL) && (head->result != tc)) { + /* this means that this sequence is an initial part + * of a previously defined one. + */ + fprintf(stderr, "Conflicting entries found when scanning %s\n", + identifier); + return(0); + } else { + head->result = tc; + return(1); /* done */ + } +} + +static +GetDefinition() +{ + stringWithLength *string; + int Tc; + + GetWS(); + if ((string = GetAlphaMericString()) == 0) { + return(0); + } + string->array[string->length] = 0; + if (doPaste) { + if ((Tc = (*GetTc)(string->array)) == -1) { + if (picky) { + fprintf(stderr, "%s: unknown 3270 key identifier\n", + string->array); + } + Tc = STATE_NULL; + } + } else { + Tc = STATE_NULL; /* XXX ? */ + } + GetWS(); + if (!GetCharacter('=')) { + fprintf(stderr, + "Required equal sign after 3270 key identifier %s missing\n", + string->array); + return(0); + } + GetWS(); + if (!GetInput(Tc, string->array)) { + fprintf(stderr, "Missing definition part for 3270 key %s\n", + string->array); + return(0); + } else { + GetWS(); + while (GetCharacter('|')) { +# ifdef DEBUG + if (debug) { + fprintf(stderr, " or "); + } +# endif /* DEBUG */ + GetWS(); + if (!GetInput(Tc, string->array)) { + fprintf(stderr, "Missing definition part for 3270 key %s\n", + string->array); + return(0); + } + GetWS(); + } + } + GetWS(); + if (!GetCharacter(';')) { + fprintf(stderr, "Missing semi-colon for 3270 key %s\n", string->array); + return(0); + } +# ifdef DEBUG + if (debug) { + fprintf(stderr, ";\n"); + } +# endif /* DEBUG */ + return(1); +} + + +static +GetDefinitions() +{ + if (!GetDefinition()) { + return(0); + } else { + while (GetDefinition()) { + ; + } + } + return(1); +} + +static +GetBegin() +{ + GetWS(); + if (!GetCharacter('{')) { + return(0); + } + return(1); +} + +static +GetEnd() +{ + GetWS(); + if (!GetCharacter('}')) { + return(0); + } + return(1); +} + +static +GetName() +{ + if (!GetAlphaMericString()) { + return(0); + } + GetWS(); + while (GetAlphaMericString()) { + GetWS(); + } + return(1); +} + +static +GetNames() +{ + GetWS(); + if (!GetName()) { + return(0); + } else { + GetWS(); + while (GetCharacter('|')) { + GetWS(); + if (!GetName()) { + return(0); + } + } + } + return(1); +} + +static +GetEntry0() +{ + if (!GetBegin()) { + fprintf(stderr, "no '{'\n"); + return(0); + } else if (!GetDefinitions()) { + fprintf(stderr, "unable to parse the definitions\n"); + return(0); + } else if (!GetEnd()) { + fprintf(stderr, "No '}' or scanning stopped early due to error.\n"); + return(0); + } else { + /* done */ + return(1); + } +} + + +static +GetEntry() +{ + if (!GetNames()) { + fprintf(stderr, "Invalid name field in entry.\n"); + return(0); + } else { + return(GetEntry0()); + } +} + +/* position ourselves within a given filename to the entry for the current + * KEYBD (or TERM) variable + */ + +Position(filename, keybdPointer) +char *filename; +char *keybdPointer; +{ + lexicon lex; + stringWithLength *name = 0; + stringWithLength *oldName; +# define Return(x) {doPaste = 1; return(x);} + + doPaste = 0; + + if ((ourFile = fopen(filename, "r")) == NULL) { +# if !defined(MSDOS) + fprintf(stderr, "Unable to open file %s\n", filename); +# endif /* !defined(MSDOS) */ + Return(0); + } + lex = Get(); + while (lex.type != LEX_END_OF_FILE) { + UnGet(lex); + /* now, find an entry that is our type. */ + GetWS(); + oldName = name; + if ((name = GetAlphaMericString()) != 0) { + if (!ustrcmp(name->array, keybdPointer)) { + /* need to make sure there is a name here... */ + lex.type = LEX_CHAR; + lex.value = 'a'; + UnGet(lex); + Return(1); + } + } else if (GetCharacter('|')) { + ; /* more names coming */ + } else { + lex = Get(); + UnGet(lex); + if (lex.type != LEX_END_OF_FILE) { + if (!GetEntry0()) { /* start of an entry */ + fprintf(stderr, + "error was in entry for %s in file %s\n", + (oldName)? oldName->array:"(unknown)", filename); + Return(0); + } + } + } + lex = Get(); + } +#if !defined(MSDOS) + fprintf(stderr, "Unable to find entry for %s in file %s\n", keybdPointer, + filename); +#endif /* !defined(MSDOS) */ + Return(0); +} + +char * +strsave(string) +char *string; +{ + char *p; + extern char *malloc(); + + p = malloc((unsigned int)strlen(string)+1); + if (p != 0) { + strcpy(p, string); + } + return(p); +} + + +/* + * InitControl - our interface to the outside. What we should + * do is figure out keyboard (or terminal) type, set up file pointer + * (or string pointer), etc. + */ + +state * +InitControl(keybdPointer, pickyarg, translator) +char *keybdPointer; +int pickyarg; /* Should we be picky? */ +int (*translator)(); /* Translates ascii string to integer */ +{ + extern char *getenv(); + int GotIt; + + picky = pickyarg; + GetTc = translator; + + if (keybdPointer == 0) { + keybdPointer = getenv("KEYBD"); + } + if (keybdPointer == 0) { + keybdPointer = getenv("TERM"); + } + + /* + * Some environments have getenv() return + * out of a static area. So, save the keyboard name. + */ + if (keybdPointer) { + keybdPointer = strsave(keybdPointer); + } + environPointer = getenv("MAP3270"); + if (environPointer + && (environPointer[0] != '/') +#if defined(MSDOS) + && (environPointer[0] != '\\') +#endif /* defined(MSDOS) */ + && (strncmp(keybdPointer, environPointer, + strlen(keybdPointer) != 0) + || (environPointer[strlen(keybdPointer)] != '{'))) /* } */ + { + environPointer = 0; + } + + if ((!environPointer) +#if defined(MSDOS) + || (*environPointer == '\\') +#endif /* defined(MSDOS) */ + || (*environPointer == '/')) { + usePointer = 0; + GotIt = 0; + if (!keybdPointer) { +#if !defined(MSDOS) + fprintf(stderr, "%s%s%s%s", + "Neither the KEYBD environment variable nor the TERM ", + "environment variable\n(one of which is needed to determine ", + "the type of keyboard you are using)\n", + "is set. To set it, say 'setenv KEYBD '\n"); +#endif /* !defined(MSDOS) */ + } else { + if (environPointer) { + GotIt = Position(environPointer, keybdPointer); + } + if (!GotIt) { + GotIt = Position("/etc/map3270", keybdPointer); + } + } + if (!GotIt) { + if (environPointer) { + GotIt = Position(environPointer, "unknown"); + } + if (!GotIt) { + GotIt = Position("/etc/map3270", keybdPointer); + } + } + if (!GotIt) { +#if !defined(MSDOS) + fprintf(stderr, "Using default key mappings.\n"); +#endif /* !defined(MSDOS) */ + usePointer = 1; /* flag use of non-file */ + whichkey = keysgeneric; + environPointer = *whichkey; /* use default table */ + } + } else { + usePointer = 1; + } + (void) GetEntry(); + return(firstentry.address); +} diff --git a/usr.bin/tn3270/ascii/map3270.h b/usr.bin/tn3270/ascii/map3270.h new file mode 100644 index 0000000..f8d6e5c --- /dev/null +++ b/usr.bin/tn3270/ascii/map3270.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)map3270.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Declaration for map3270.c. + */ + +extern state + *InitControl(); diff --git a/usr.bin/tn3270/ascii/mset.c b/usr.bin/tn3270/ascii/mset.c new file mode 100644 index 0000000..508fe66 --- /dev/null +++ b/usr.bin/tn3270/ascii/mset.c @@ -0,0 +1,410 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mset.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * this program outputs the user's 3270 mapping table in a form suitable + * for inclusion in the environment. Typically, this might be used + * by: + * setenv MAP3270 "`mset`" + */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include "../ctlr/function.h" + +#include "state.h" +#include "map3270.h" + +#include "../api/astosc.h" + +#include "../general/globals.h" + +struct regstate { + char *result; + char *match_start; + char *match_end; /* start of NEXT state's match string */ + struct regstate *forward; + struct regstate *backward; +}; + +static struct regstate regstates[500], *rptr= 0; /* for sorting states */ +static char array[5000]; /* lot's of room */ +static int toshell = 0; /* export to shell */ +static int numbchars = 0; /* number of chars in envir. var */ + +static int +MyStrcmp(str1, str2) +char *str1, *str2; +{ + if (strncmp(str1, "PFK", 3) == 0 && strncmp(str2, "PFK", 3) == 0 + && strlen(str1) != strlen(str2)) { + return(strlen(str1) - strlen(str2)); + } + return(strcmp(str1, str2)); +} + +static void +forwRegister(regptr, sptr) +struct regstate *regptr, *sptr; +{ + + regptr->forward = sptr->forward; + regptr->backward = sptr; + (sptr->forward)->backward = regptr; + sptr->forward = regptr; +} + +static void +backRegister(regptr, sptr) +struct regstate *regptr, *sptr; +{ + + regptr->forward = sptr; + regptr->backward = sptr->backward; + (sptr->backward)->forward = regptr; + sptr->backward = regptr; +} + +static struct regstate * +doRegister(regptr) +register struct regstate *regptr; +{ + static struct regstate *pivot = regstates; + register struct regstate *sptr = pivot; + int check; + + if (pivot == regstates) { /* first time called */ + pivot->forward = regptr; + regptr->backward = pivot++; + pivot->backward = regptr; + regptr->forward = pivot++; + return(++regptr); + } + if ((check = MyStrcmp(regptr->result, pivot->result)) < 0) { + while (check < 0) { + if (sptr->backward == regstates) { + backRegister(regptr, sptr); + pivot = pivot->backward; + return(++regptr); + } + sptr = sptr->backward; + check = MyStrcmp(regptr->result, sptr->result); + } + forwRegister(regptr, sptr); + pivot = pivot->backward; + return(++regptr); + } + while (check > 0) { + if ((sptr->forward)->result == 0) { + forwRegister(regptr, sptr); + pivot = pivot->forward; + return(++regptr); + } + sptr = sptr->forward; + check = MyStrcmp(regptr->result, sptr->result); + } + backRegister(regptr, sptr); + if (pivot->forward->result) { + pivot = pivot->forward; + } + return(++regptr); +} + +static char * +addString(strcount, character) +int strcount; +char character; +{ + static char *string = array; + int i; + + if (rptr->match_start == 0) { + rptr->match_start = string; + for (i=0; i < strcount; i++) { + *string++ = *((rptr-1)->match_start+i); + } + } + *string++ = character; + return(string); +} + +static char savename[20] = " "; /* for deciding if name is new */ + +static void +printString(string, begin, tc_name) +register char *string; +char *begin, *tc_name; +{ + register char *st1, *st2; + register int pchar; + static char suffix = 'A'; + int new = strcmp(savename, tc_name); + char delim = new ? ';' : '|'; + char *uncontrol(); + + st1 = begin; + + numbchars += 5 + (new ? strlen(tc_name) : -1); + if (toshell && numbchars > 1011) { + new = 1; + delim = ';'; + numbchars = 5 + strlen(tc_name); + printf(";\nsetenv MAP3270%c ", suffix++); + } + if (strcmp(" ", savename)) { + if (toshell) { + printf("%c%c", '\\', delim); + } + else { + printf("%c", delim); + } + } + else { + numbchars -= 2; + } + if (toshell && new) { + printf("%s=%c'", tc_name,'\\'); + } + else if (new) { + printf("%s='", tc_name); + } + else if (toshell) { + printf("%c'", '\\'); + } + else { + printf("'"); + } + (void) strcpy(savename, tc_name); + while (st1 != string) { + if (toshell && numbchars >= 1016) { /* leave room for ctrl and delim */ + numbchars = 0; + printf(";\nsetenv MAP3270%c ", suffix++); + } + pchar = 0xff&(*st1++); + switch (pchar) { + case '"': + case '!': + case '$': + case '(': + case ')': + case ' ': + case ';': + case '&': + case '|': + case '>': + case '<': + case '`': + case '#': + numbchars += 2; + if (toshell) { + printf("%c%c", '\\', pchar); + } + else { + printf("%c", pchar); + } + break; + case '\\': + case '\'': + numbchars += 4; + if (toshell) { + printf("%c%c%c%c", '\\', '\\', '\\', pchar); + } + else { + printf("%c%c", '\\', pchar); + } + break; + case '^': + numbchars += 3; + if (toshell) { + printf("%c%c%c", '\\', '\\', pchar); + } + else { + printf("%c%c", '\\', pchar); + } + break; + default: + st2 = uncontrol(pchar); + while ((pchar = *st2++) != 0) { + switch (pchar) { + case '"': + case '!': + case '$': + case '(': + case ')': + case ' ': + case ';': + case '&': + case '|': + case '>': + case '<': + case '`': + case '#': + case '\\': + case '\'': + if (toshell) { + numbchars += 2; + printf("%c%c", '\\', pchar); + } + else { + printf("%c", pchar); + } + break; + default: + numbchars++; + printf("%c", pchar); + break; + } + } + break; + } + } + numbchars += 2; + if (toshell) { + printf("%c'", '\\'); + } + else { + printf("'"); + } +} + +static void +recurse(strcount, head) +state *head; +int strcount; +{ + /* if there is a left, + * recurse on left, + * if there is no down, + * print the string to here + * else, + * add the current match to the string, + * recurse. + * exit. + */ + + if (head->next) { + recurse(strcount, head->next); + } + if (head->result != STATE_GOTO) { + rptr->match_end = addString(strcount, head->match); + rptr->result = astosc[head->result].name; + rptr = doRegister(rptr); + } else { + (void) addString(strcount, head->match); + recurse(strcount+1, head->address); + strcount--; + } + return; +} + + +main(argc, argv) +int argc; +char *argv[]; +{ + state *head; + char *keybdPointer = (char *) 0; + char *commandName = argv[0]; + extern char *getenv(); + int picky = 0; + + while ((argc > 1) && (argv[1][0] == '-')) { + if (!strcmp(argv[1], "-picky")) { + picky++; + } else if (!strcmp(argv[1], "-shell")) { + toshell++; + } else { + fprintf(stderr, "usage: %s [-picky] [-shell] [keyboardname]\n", + commandName); + exit(1); + /*NOTREACHED*/ + } + argv++; + argc--; + } + if (argc == 2) { + keybdPointer = argv[1]; + } else if (argc > 2) { + fprintf(stderr, "usage: %s [-picky] [-shell] [keyboardname]\n", + commandName); + exit(1); + /*NOTREACHED*/ + } + head = InitControl(keybdPointer, picky, ascii_to_index); + if (!head) { + return(1); + } + if (keybdPointer == 0) { + keybdPointer = getenv("KEYBD"); + } + if (keybdPointer == 0) { + keybdPointer = getenv("TERM"); + } + if (keybdPointer == 0) { + keybdPointer = "3a"; /* use 3a as the terminal */ + } + if (toshell) { + printf("set noglob;\nsetenv MAP3270 "); + } + printf("%s{", keybdPointer); + numbchars = 2 + strlen(keybdPointer); + /* now, run through the table registering entries */ + rptr = regstates + 2; + recurse(0, head); + /* now print them out */ + for (rptr = regstates[0].forward; rptr->result != 0; + rptr = rptr->forward) { + printString(rptr->match_end, rptr->match_start, rptr->result); + } + if (toshell) { + printf("%c;};\nunset noglob;\n", '\\'); + } + else { + printf(";}\n"); + } + return(0); +} diff --git a/usr.bin/tn3270/ascii/state.h b/usr.bin/tn3270/ascii/state.h new file mode 100644 index 0000000..562522a --- /dev/null +++ b/usr.bin/tn3270/ascii/state.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)state.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_STATE + +/* this defines the state structure used by the key mapping routines */ + + +#define STATE_NULL -1 /* Falls off edge */ +#define STATE_GOTO -2 /* GOTO internal state */ + +#define state struct State +struct State { + int match; /* character to match */ + int result; /* 3270 control code */ + state *next; /* next entry in this same state */ + state *address; /* if goto, where is next state */ +}; diff --git a/usr.bin/tn3270/ascii/termin.c b/usr.bin/tn3270/ascii/termin.c new file mode 100644 index 0000000..a783189 --- /dev/null +++ b/usr.bin/tn3270/ascii/termin.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)termin.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* this takes characters from the keyboard, and produces 3270 keystroke + codes + */ + +#include +#include + +#include "../general/general.h" +#include "../ctlr/function.h" +#include "../ctlr/externs.h" +#include "../ctlr/declare.h" + +#include "../api/astosc.h" +#include "state.h" + +#include "../general/globals.h" + +#define IsControl(c) (!isprint(c) || (isspace(c) && ((c) != ' '))) + +#define NextState(x) (x->next) + +/* XXX temporary - hard code in the state table */ + +#define MATCH_ANY 0xff /* actually, match any character */ + + +static unsigned char + ourBuffer[100], /* where we store stuff */ + *ourPHead = ourBuffer, /* first character in buffer */ + *ourPTail = ourBuffer, /* where next character goes */ + *TransPointer = 0; /* For transparent mode data */ + +static int InControl; +static int WaitingForSynch; + +static struct astosc + *spacePTR = 0; /* Space is hard to enter */ + +static state + *headOfControl = 0; /* where we enter code state table */ + +#define FullChar ((ourPTail+5) >= ourBuffer+sizeof ourBuffer) +#define EmptyChar (ourPTail == ourPHead) + + +/* + * init_keyboard() + * + * Initialize the keyboard variables. + */ + +void +init_keyboard() +{ + ourPHead = ourPTail = ourBuffer; + InControl = 0; + WaitingForSynch = 0; +} + + +/* + * Initialize the keyboard mapping file. + */ + +void +InitMapping() +{ + extern state *InitControl(); + register struct astosc *ptr; + + if (!headOfControl) { + /* need to initialize */ + headOfControl = InitControl((char *)0, 0, ascii_to_index); + if (!headOfControl) { /* should not occur */ + quit(); + } + for (ptr = &astosc[0]; ptr <= &astosc[highestof(astosc)]; ptr++) { + if (ptr->function == FCN_SPACE) { + spacePTR = ptr; + } + } + } +} + + +/* AddChar - put a function index in our buffer */ + +static void +AddChar(c) +int c; +{ + if (!FullChar) { + *ourPTail++ = c; + } else { + RingBell("Typeahead buffer full"); + } +} + +/* FlushChar - put everything where it belongs */ + +static void +FlushChar() +{ + ourPTail = ourBuffer; + ourPHead = ourBuffer; +} + +/*ARGSUSED*/ +void +TransInput(onoff, mode) +int mode; /* Which KIND of transparent input */ +int onoff; /* Going in, or coming out */ +{ + if (onoff) { + /* Flush pending input */ + FlushChar(); + TransPointer = ourBuffer; + } else { + } +} + +int +TerminalIn() +{ + /* send data from us to next link in stream */ + int work = 0; + register struct astosc *ptr; + + while (!EmptyChar) { /* send up the link */ + if (*ourPHead == ' ') { + ptr = spacePTR; + } else { + ptr = &astosc[*ourPHead]; + } + if (AcceptKeystroke(ptr->scancode, ptr->shiftstate) == 1) { + ourPHead++; + work = 1; + } else { + break; + } + } + + if (EmptyChar) { + FlushChar(); + } + /* return value answers question: "did we do anything useful?" */ + return work; +} + +int +DataFromTerminal(buffer, count) +register char *buffer; /* the data read in */ +register int count; /* how many bytes in this buffer */ +{ + register state *regControlPointer; + register char c; + register int result; + int origCount; + extern int bellwinup; + static state *controlPointer; + + if (TransPointer) { + int i; + + if ((count+TransPointer) >= (ourBuffer+sizeof ourBuffer)) { + i = ourBuffer+sizeof ourBuffer-TransPointer; + } else { + i = count; + } + while (i--) { + c = (*buffer++)&0x7f; + *TransPointer++ = c|0x80; + if (c == '\r') { + SendTransparent((char *)ourBuffer, TransPointer-ourBuffer); + TransPointer = 0; /* Done */ + break; + } + } + return count; + } + + if (bellwinup) { + void BellOff(); + + BellOff(); + } + + origCount = count; + + while (count) { + c = *buffer++&0x7f; + count--; + + if (!InControl && !IsControl(c)) { + AddChar(c); /* add ascii character */ + } else { + if (!InControl) { /* first character of sequence */ + InControl = 1; + controlPointer = headOfControl; + } + /* control pointer points to current position in state table */ + for (regControlPointer = controlPointer; ; + regControlPointer = NextState(regControlPointer)) { + if (!regControlPointer) { /* ran off end */ + RingBell("Invalid control sequence"); + regControlPointer = headOfControl; + InControl = 0; + count = 0; /* Flush current input */ + break; + } + if ((regControlPointer->match == c) /* hit this character */ + || (regControlPointer->match == MATCH_ANY)) { + result = regControlPointer->result; + if (result == STATE_GOTO) { + regControlPointer = regControlPointer->address; + break; /* go to next character */ + } + if (WaitingForSynch) { + if (astosc[result].function == FCN_SYNCH) { + WaitingForSynch = 0; + } else { + void RingBell(); + + RingBell("Need to type synch character"); + } + } + else if (astosc[result].function == FCN_FLINP) { + FlushChar(); /* Don't add FLINP */ + } else { + if (astosc[result].function == FCN_MASTER_RESET) { + FlushChar(); + } + AddChar(result); /* add this code */ + } + InControl = 0; /* out of control now */ + break; + } + } + controlPointer = regControlPointer; /* save state */ + } + } + (void) TerminalIn(); /* try to send data */ + return(origCount-count); +} diff --git a/usr.bin/tn3270/ctlr/3180.kbd b/usr.bin/tn3270/ctlr/3180.kbd new file mode 100644 index 0000000..1fc7204 --- /dev/null +++ b/usr.bin/tn3270/ctlr/3180.kbd @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)3180.kbd 8.1 (Berkeley) 6/6/93 + */ + +/* + * keynumber [ scancode [ unshifted [ shifted [ alted [ shiftalted ] ] ] ] ] + * + * keynumber is in decimal, and starts in column 1. + * scancode is hexadecimal. + * unshifted, etc. - these are either a single ascii character, + * or the name of a function or an AID-generating key. + * + * all fields are separated by a single space. + */ +1 0e ` ~ +2 16 1 VERTICAL_BAR +3 1e 2 @ +4 26 3 # +5 25 4 $ +6 2e 5 % +7 36 6 ^ +8 3d 7 & +9 3e 8 * +10 46 9 ( +11 45 0 ) +12 4e - _ +13 55 = + +14 5d +15 66 LEFT +16 0d TAB +17 15 q Q +18 1d w W +19 24 e E +20 2d r R +21 2c t T +22 35 y Y +23 3c u U +24 43 i I +25 44 o O +26 4d p P +27 54 CENTSIGN ! +28 5b \ | +29 5c +30 14 CAPS_LOCK +31 1c a A +32 1b s S +33 23 d D +34 2b f F +35 34 g G +36 33 h H +37 3b j J +38 42 k K +39 4b l L +40 4c ; : +41 52 ' " +42 53 { } +43 5a NL +44 12 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +45 13 < > +46 1a z Z +47 22 x X +48 21 c C +49 2a v V +50 32 b B +51 31 n N +52 3a m M +53 41 , , +54 49 . . +55 4a / ? +56 51 +57 59 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +58 11 RESET NULL DVCNL +59 +60 19 MAKE_ALT MAKE_ALT MAKE_ALT +61 29 SPACE SPACE +62 39 MAKE_ALT MAKE_ALT MAKE_ALT +63 +64 58 ENTER +65 06 CLEAR +66 0c NULL NULL EINP +67 0b EEOF +68 0a +69 09 +70 05 ATTN NULL TREQ +71 04 +72 03 +73 83 +74 01 +75 67 PA1 DP +76 64 BTAB +77 +78 61 LEFT NULL LEFT2 +79 +80 6e PA2 FM +81 65 INSRT +82 63 UP +83 62 NULL NULL HOME +84 60 DOWN +85 6f +86 6d DELETE +87 +88 6a RIGHT NULL RIGHT2 +89 +90 76 +91 6c 7 +92 6b 4 +93 69 1 +94 68 +95 77 +96 75 8 +97 73 5 +98 72 2 +99 70 0 +100 7e , +101 7d 9 +102 74 6 +103 7a 3 +104 71 . +105 84 SPACE +106 7c TAB +107 7b - +108 79 ENTER +109 78 +110 07 PF1 +111 0f PF2 +112 17 PF3 +113 1f PF4 +114 27 PF5 +115 2f PF6 +116 37 PF7 +117 3f PF8 NULL MONOCASE +118 47 PF9 +119 4f PF10 +120 56 PF11 +121 5e PF12 +122 08 PF13 +123 10 PF14 +124 18 PF15 +125 20 PF16 +126 28 PF17 +127 30 PF18 +128 38 PF19 +129 40 PF20 +130 48 PF21 +131 50 PF22 +132 57 PF23 +133 5f PF24 +134 92 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +135 D9 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +136 99 BREAK_ALT BREAK_ALT BREAK_ALT +137 B9 BREAK_ALT BREAK_ALT BREAK_ALT diff --git a/usr.bin/tn3270/ctlr/3270pc.kbd b/usr.bin/tn3270/ctlr/3270pc.kbd new file mode 100644 index 0000000..df75046 --- /dev/null +++ b/usr.bin/tn3270/ctlr/3270pc.kbd @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)3270pc.kbd 8.1 (Berkeley) 6/6/93 + */ + +/* + * keynumber [ scancode [ unshifted [ shifted [ alted [ shiftalted ] ] ] ] ] + * + * keynumber is in decimal, and starts in column 1. + * scancode is hexadecimal. + * unshifted, etc. - these are either a single ascii character, + * or the name of a function or an AID-generating key. + * + * all fields are separated by a single space. + */ +1 0e ` ~ +2 16 1 ! +3 1e 2 @ +4 26 3 # +5 25 4 $ +6 2e 5 % +7 36 6 ^ +8 3d 7 & +9 3e 8 * +10 46 9 ( +11 45 0 ) +12 4e - _ +13 55 = + +14 5d +15 66 LEFT +16 0d TAB BTAB +17 15 q Q +18 1d w W +19 24 e E +20 2d r R +21 2c t T +22 35 y Y +23 3c u U +24 43 i I +25 44 o O +26 4d p P +27 54 [ { +28 5b \ | +29 5c +30 14 CAPS_LOCK +31 1c a A +32 1b s S +33 23 d D +34 2b f F +35 34 g G +36 33 h H +37 3b j J +38 42 k K +39 4b l L +40 4c ; : +41 52 ' " +42 53 ] } +43 5a NL +44 12 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +45 13 < > +46 1a z Z +47 22 x X +48 21 c C +49 2a v V +50 32 b B +51 31 n N +52 3a m M +53 41 , < +54 49 . > +55 4a / ? +56 51 +57 59 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +58 11 RESET NULL DVCNL +59 +60 19 MAKE_ALT MAKE_ALT MAKE_ALT +61 29 SPACE SPACE +62 39 MAKE_ALT MAKE_ALT MAKE_ALT +63 +64 58 ENTER +65 06 CLEAR NULL TEST +66 0c NULL NULL ATTN +67 0b EEOF NULL EINP +68 0a +69 09 MAKE_CTRL +70 05 ATTN NULL TREQ +71 04 +72 03 +73 83 +74 01 +75 67 PA1 DP +76 64 BTAB +77 +78 61 LEFT NULL LEFT2 +79 +80 6e PA2 FM +81 65 INSRT +82 63 UP +83 62 NULL NULL HOME +84 60 DOWN +85 6f PA3 +86 6d DELETE +87 +88 6a RIGHT NULL RIGHT2 +89 +90 76 +91 6c 7 +92 6b 4 +93 69 1 +94 68 +95 77 +96 75 8 +97 73 5 +98 72 2 +99 70 0 +100 7e , +101 7d 9 +102 74 6 +103 7a 3 +104 71 . +105 84 SPACE +106 7c TAB +107 7b - +108 79 ENTER +109 78 +110 07 PF1 +111 0f PF2 +112 17 PF3 +113 1f PF4 +114 27 PF5 +115 2f PF6 +116 37 PF7 +117 3f PF8 NULL MONOCASE +118 47 PF9 +119 4f PF10 +120 56 PF11 +121 5e PF12 +122 08 PF13 +123 10 PF14 +124 18 PF15 +125 20 PF16 +126 28 PF17 +127 30 PF18 +128 38 PF19 +129 40 PF20 +130 48 PF21 +131 50 PF22 +132 57 PF23 +133 5f PF24 +134 92 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +135 D9 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +136 99 BREAK_ALT BREAK_ALT BREAK_ALT +137 B9 BREAK_ALT BREAK_ALT BREAK_ALT diff --git a/usr.bin/tn3270/ctlr/api.c b/usr.bin/tn3270/ctlr/api.c new file mode 100644 index 0000000..1113295 --- /dev/null +++ b/usr.bin/tn3270/ctlr/api.c @@ -0,0 +1,755 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)api.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This file implements the API used in the PC version. + */ + +#include + +#include "api.h" +#include "../general/general.h" + +#include "../api/disp_asc.h" + +#include "screen.h" +#include "hostctlr.h" +#include "oia.h" + +#include "../general/globals.h" + +int apitrace = 0; + +/* + * Some defines for things we use internally. + */ + +#define PS_SESSION_ID 23 +#define BUF_SESSION_ID 0 + +/* + * General utility routines. + */ + +#if defined(MSDOS) + +#if defined(LINT_ARGS) +static void movetous(char *, int, int, int); +static void movetothem(int, int, char *, int); +#endif /* defined(LINT_ARGS) */ + +#define access_api(foo,length,copyin) (foo) +#define unaccess_api(foo,goo,length,copyout) + +static void +movetous(parms, es, di, length) +char *parms; +int es, di; +int length; +{ + char far *farparms = parms; + + movedata(es, di, FP_SEG(farparms), FP_OFF(farparms), length); + if (apitrace) { + Dump('(', parms, length); + } +} + +static void +movetothem(es, di, parms, length) +int es, di; +char *parms; +int length; +{ + char far *farparms = parms; + + movedata(FP_SEG(farparms), FP_OFF(farparms), es, di, length); + if (apitrace) { + Dump(')', parms, length); + } +} +#endif /* defined(MSDOS) */ + +#if defined(unix) +extern char *access_api(); +extern void movetous(), movetothem(), unaccess_api(); +#endif /* defined(unix) */ + + +/* + * Supervisor Services. + */ + +static void +name_resolution(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + NameResolveParms parms; + + movetous((char *) &parms, sregs->es, regs->x.di, sizeof parms); + + regs->h.cl = 0; + if (memcmp((char *)&parms, NAME_SESSMGR, sizeof parms.gate_name) == 0) { + regs->x.dx = GATE_SESSMGR; + } else if (memcmp((char *)&parms, NAME_KEYBOARD, + sizeof parms.gate_name) == 0) { + regs->x.dx = GATE_KEYBOARD; + } else if (memcmp((char *)&parms, NAME_COPY, sizeof parms.gate_name) == 0) { + regs->x.dx = GATE_COPY; + } else if (memcmp((char *)&parms, NAME_OIAM, sizeof parms.gate_name) == 0) { + regs->x.dx = GATE_OIAM; + } else { + regs->h.cl = 0x2e; /* Name not found */ + } + regs->h.ch = 0x12; + regs->h.bh = 7; +} + +/* + * Session Information Services. + */ + +static void +query_session_id(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + QuerySessionIdParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.option_code != 0x01) { + parms.rc = 0x0d; /* Invalid option code */ +#ifdef NOTOBS + } else if ((parms.data_code != 0x45) && (parms.data_code != 0x00/*OBS*/)) { + parms.rc = 0x0b; +#endif /* NOTOBS */ + } else { + NameArray list; + + movetous((char *)&list, FP_SEG(parms.name_array), + FP_OFF(parms.name_array), sizeof list); + if ((list.length < 14) || (list.length > 170)) { + parms.rc = 0x12; + } else { + list.number_matching_session = 1; + list.name_array_element.short_name = parms.data_code; + list.name_array_element.type = TYPE_DFT; + list.name_array_element.session_id = PS_SESSION_ID; + memcpy(list.name_array_element.long_name, "ONLYSESS", + sizeof list.name_array_element.long_name); + movetothem(FP_SEG(parms.name_array), + FP_OFF(parms.name_array), (char *)&list, sizeof list); + parms.rc = 0; + } + } + parms.function_id = 0x6b; + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +static void +query_session_parameters(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + QuerySessionParametersParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc !=0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else { + parms.rc = 0; + parms.session_type = TYPE_DFT; + parms.session_characteristics = 0; /* Neither EAB nor PSS */ + parms.rows = MaxNumberLines; + parms.columns = MaxNumberColumns; + parms.presentation_space = 0; + } + parms.function_id = 0x6b; + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +static void +query_session_cursor(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + QuerySessionCursorParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else { + parms.rc = 0; + parms.cursor_type = CURSOR_BLINKING; /* XXX what is inhibited? */ + parms.row_address = ScreenLine(CursorAddress); + parms.column_address = ScreenLineOffset(CursorAddress); + } + + parms.function_id = 0x6b; + movetothem(sregs->es, regs->x.di, (char *) &parms, sizeof parms); +} + +/* + * Keyboard Services. + */ + + +static void +connect_to_keyboard(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + ConnectToKeyboardParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else if (parms.intercept_options != 0) { + parms.rc = 0x01; + } else { + parms.rc = 0; + parms.first_connection_identifier = 0; + } + parms.function_id = 0x62; + + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +static void +disconnect_from_keyboard(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + DisconnectFromKeyboardParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else if (parms.connectors_task_id != 0) { + parms.rc = 04; /* XXX */ + } else { + parms.rc = 0; + } + parms.function_id = 0x62; + + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +static void +write_keystroke(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + WriteKeystrokeParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else if (parms.connectors_task_id != 0) { + parms.rc = 0x04; + } else { + parms.number_of_keys_sent = 0; + parms.rc = 0; + if (parms.options == OPTION_SINGLE_KEYSTROKE) { + KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry; + + if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) { + parms.rc = 0x10; /* XXX needs 0x12 too! */ + } + parms.number_of_keys_sent++; + } else if (parms.options == OPTION_MULTIPLE_KEYSTROKES) { + KeystrokeList + list, + far *atlist = parms.keystroke_specifier.keystroke_list; + KeystrokeEntry + entry[10], /* 10 at a time */ + *ourentry, + far *theirentry; + int + todo; + + movetous((char *)&list, FP_SEG(atlist), + FP_OFF(atlist), sizeof *atlist); + todo = list.length/2; + ourentry = entry+(highestof(entry)+1); + theirentry = &atlist->keystrokes; + + while (todo) { + if (ourentry > &entry[highestof(entry)]) { + int thistime; + + thistime = todo; + if (thistime > numberof(entry)) { + thistime = numberof(entry); + } + movetous((char *)entry, FP_SEG(theirentry), + FP_OFF(theirentry), thistime*sizeof *theirentry); + theirentry += thistime; + ourentry = entry; + } + if (AcceptKeystroke(ourentry->scancode, + ourentry->shift_state) == 0) { + parms.rc = 0x10; /* XXX needs 0x12 too! */ + break; + } + parms.number_of_keys_sent++; + ourentry++; + todo--; + } + } else { + parms.rc = 0x01; + } + } + parms.function_id = 0x62; + + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +/* XXX */ +} + + +static void +disable_input(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + DisableInputParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else if (parms.connectors_task_id != 0) { + parms.rc = 0x04; + } else { + SetOiaApiInhibit(&OperatorInformationArea); + parms.rc = 0; + } + parms.function_id = 0x62; + + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +static void +enable_input(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + EnableInputParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else if (parms.connectors_task_id != 0) { + parms.rc = 0x04; + } else { + ResetOiaApiInhibit(&OperatorInformationArea); + parms.rc = 0; + } + parms.function_id = 0x62; + + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +/* + * Copy Services. + */ + +static +copy_subroutine(target, source, parms, what_is_user, length) +BufferDescriptor *target, *source; +CopyStringParms *parms; +int what_is_user; +#define USER_IS_TARGET 0 +#define USER_IS_SOURCE 1 +{ +#define TARGET_NO_EAB 1 +#define SOURCE_NO_EAB 2 +#define TARGET_PC 4 +#define SOURCE_PC 8 +#define NO_FIELD_ATTRIBUTES 16 + int needtodo = 0; + int access_length; + char far *input; + char far *output; + char far *access_pointer; + + if ((target->characteristics^source->characteristics) + &CHARACTERISTIC_EAB) { + if (target->characteristics&CHARACTERISTIC_EAB) { + needtodo |= TARGET_NO_EAB; /* Need to bump for EAB in target */ + } else { + needtodo |= SOURCE_NO_EAB; /* Need to bump for EAB in source */ + } + } + if (target->session_type != source->session_type) { + if (target->session_type == TYPE_PC) { + needtodo |= TARGET_PC; /* scan codes to PC */ + } else { + needtodo |= SOURCE_PC; /* PC to scan codes */ + } + } + if ((parms->copy_mode©_MODE_FIELD_ATTRIBUTES) == 0) { + needtodo |= NO_FIELD_ATTRIBUTES; + } + access_length = length; + if (what_is_user == USER_IS_TARGET) { + if (target->characteristics&CHARACTERISTIC_EAB) { + access_length *= 2; + } + input = (char far *) &Host[source->begin]; + access_pointer = target->buffer; + output = access_api(target->buffer, access_length, 0); + } else { + if (source->characteristics&CHARACTERISTIC_EAB) { + access_length *= 2; + } + access_pointer = source->buffer; + input = access_api(source->buffer, access_length, 1); + output = (char far *) &Host[target->begin]; + } + while (length--) { + if (needtodo&TARGET_PC) { + *output++ = disp_asc[*input++]; + } else if (needtodo&SOURCE_PC) { + *output++ = asc_disp[*input++]; + } else { + *output++ = *input++; + } + if (needtodo&TARGET_NO_EAB) { + input++; + } else if (needtodo&SOURCE_NO_EAB) { + *output++ = 0; /* Should figure out good EAB? */ + } + } + if (what_is_user == USER_IS_TARGET) { + unaccess_api(target->buffer, access_pointer, access_length, 1); + } else { + unaccess_api(source->buffer, access_pointer, access_length, 0); + } +} + + +static void +copy_string(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + CopyStringParms parms; + BufferDescriptor *target = &parms.target, *source = &parms.source; + int length; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + length = 1+parms.source_end-source->begin; + if ((parms.rc != 0) || (parms.function_id !=0)) { + parms.rc = 0x0c; + } else if (target->session_id == BUF_SESSION_ID) { /* Target is buffer */ + if (source->session_id != PS_SESSION_ID) { /* A no-no */ + parms.rc = 0x2; + } else { + if ((source->begin < 0) || (source->begin > highestof(Host))) { + parms.rc = 0x06; /* invalid source definition */ + } else { + if ((source->begin+length) > highestof(Host)) { + length = highestof(Host)-source->begin; + parms.rc = 0x0f; /* Truncate */ + } + if ((source->characteristics == target->characteristics) && + (source->session_type == target->session_type)) { + if (source->characteristics&CHARACTERISTIC_EAB) { + length *= 2; + } + movetothem(FP_SEG(target->buffer), + FP_OFF(target->buffer), + (char *)&Host[source->begin], length); + } else { + copy_subroutine(target, source, &parms, + USER_IS_TARGET, length); + } + } + } + } else if (source->session_id != BUF_SESSION_ID) { + parms.rc = 0xd; + } else { + /* Send to presentation space (3270 buffer) */ + if ((target->begin < 0) || (target->begin > highestof(Host))) { + parms.rc = 0x07; /* invalid target definition */ + } if (!UnLocked) { + parms.rc = 0x03; /* Keyboard locked */ + } else if (parms.copy_mode != 0) { + parms.rc = 0x0f; /* Copy of field attr's not allowed */ + } else if (IsProtected(target->begin) || /* Make sure no protected */ + (WhereAttrByte(target->begin) != /* in range */ + WhereAttrByte(target->begin+length-1))) { + parms.rc = 0x0e; /* Attempt to write in protected */ + } else { + if ((target->begin+length) > highestof(Host)) { + length = highestof(Host)-target->begin; + parms.rc = 0x0f; /* Truncate */ + } + TurnOnMdt(target->begin); /* Things have changed */ + if ((source->characteristics == target->characteristics) && + (source->session_type == target->session_type)) { + if (source->characteristics&CHARACTERISTIC_EAB) { + length *= 2; + } + movetous((char *)&Host[target->begin], + FP_SEG(source->buffer), + FP_OFF(source->buffer), length); + } else { + copy_subroutine(target, source, &parms, USER_IS_SOURCE, length); + } + } + } + parms.function_id = 0x64; + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + + +/* + * Operator Information Area Services. + */ + +static void +read_oia_group(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + ReadOiaGroupParms parms; + + movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms); + + if ((parms.rc != 0) || (parms.function_id != 0)) { + parms.rc = 0x0c; + } else if (parms.session_id != PS_SESSION_ID) { + parms.rc = 0x02; + } else { + int group = parms.oia_group_number; + char *from; + int size; + + if ((group != API_OIA_ALL_GROUPS) && + ((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) { + } else { + if (group == API_OIA_ALL_GROUPS) { + size = API_OIA_BYTES_ALL_GROUPS; + from = (char *)&OperatorInformationArea; + } else if (group == API_OIA_INPUT_INHIBITED) { + size = sizeof OperatorInformationArea.input_inhibited; + from = (char *)&OperatorInformationArea.input_inhibited[0]; + } else { + size = 1; + from = ((char *)&OperatorInformationArea)+group; + } + movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer), + from, size); + } + } + parms.function_id = 0x6d; + movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms); +} + +/*ARGSUSED*/ +static void +unknown_op(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ + regs->h.ch = 0x12; + regs->h.cl = 0x05; +} + + +handle_api(regs, sregs) +union REGS *regs; +struct SREGS *sregs; +{ +/* + * Do we need to log this transaction? + */ + if (apitrace) { + Dump('<', (char *)regs, sizeof *regs); + Dump('<', (char *)sregs, sizeof *sregs); + } + if (regs->h.ah == NAME_RESOLUTION) { + name_resolution(regs, sregs); +#if defined(unix) + } else if (regs->h.ah == PS_OR_OIA_MODIFIED) { + while ((oia_modified == 0) && (ps_modified == 0)) { + (void) Scheduler(1); + } + oia_modified = ps_modified = 0; +#endif /* defined(unix) */ + } else if (regs->h.ah != 0x09) { + regs->h.ch = 0x12; + regs->h.cl = 0x0f; /* XXX Invalid environmental access */ + } else if (regs->x.bx != 0x8020) { + regs->h.ch = 0x12; + regs->h.cl = 0x08; /* XXX Invalid wait specified */ + } else if (regs->h.ch != 0) { + regs->x.cx = 0x1206; /* XXX Invalid priority */ + } else { + switch (regs->x.dx) { + case GATE_SESSMGR: + switch (regs->h.al) { + case QUERY_SESSION_ID: + if (regs->h.cl != 0) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + query_session_id(regs, sregs); + } + break; + case QUERY_SESSION_PARAMETERS: + if (regs->h.cl != 0) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + query_session_parameters(regs, sregs); + } + break; + case QUERY_SESSION_CURSOR: + if ((regs->h.cl != 0xff) && (regs->h.cl != 0x00/*OBS*/)) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + query_session_cursor(regs, sregs); + } + break; + default: + unknown_op(regs, sregs); + break; + } + break; + case GATE_KEYBOARD: + if (regs->h.cl != 00) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + switch (regs->h.al) { + case CONNECT_TO_KEYBOARD: + connect_to_keyboard(regs, sregs); + break; + case DISABLE_INPUT: + disable_input(regs, sregs); + break; + case WRITE_KEYSTROKE: + write_keystroke(regs, sregs); + break; + case ENABLE_INPUT: + enable_input(regs, sregs); + break; + case DISCONNECT_FROM_KEYBOARD: + disconnect_from_keyboard(regs, sregs); + break; + default: + unknown_op(regs, sregs); + break; + } + } + break; + case GATE_COPY: + if (regs->h.cl != 0xff) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + switch (regs->h.al) { + case COPY_STRING: + copy_string(regs, sregs); + break; + default: + unknown_op(regs, sregs); + break; + } + } + break; + case GATE_OIAM: + if (regs->h.cl != 0xff) { + regs->x.cx = 0x1206; + } else { + regs->x.cx = 0x1200; + switch (regs->h.al) { + case READ_OIA_GROUP: + read_oia_group(regs, sregs); + break; + default: + unknown_op(regs, sregs); + break; + } + } + break; + default: + regs->h.ch = 0x12; + regs->h.cl = 0x34; /* Invalid GATE entry */ + break; + } + } +/* + * Do we need to log this transaction? + */ + if (apitrace) { + Dump('>', (char *)regs, sizeof *regs); + Dump('>', (char *)sregs, sizeof *sregs); +#ifdef MSDOS + { char buf[10]; gets(buf); } +#endif /* MSDOS */ + } +} diff --git a/usr.bin/tn3270/ctlr/api.h b/usr.bin/tn3270/ctlr/api.h new file mode 100644 index 0000000..8004f34 --- /dev/null +++ b/usr.bin/tn3270/ctlr/api.h @@ -0,0 +1,403 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)api.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This file contains header information used by the PC API routines. + */ + +#if !defined(MSDOS) +#define far /* For 'far *' checks */ +#endif /* !defined(MSDOS) */ + +#define API_INTERRUPT_NUMBER 0x7A /* API Interrupt Number */ + +/* + * Define the gate numbers. These are returned via the Name Resolution + * service. + */ + +#define GATE_SESSMGR 1234 +#define GATE_KEYBOARD 5678 +#define GATE_COPY 9101 +#define GATE_OIAM 1121 + +/* + * The names which correspond to the above gate numbers. + */ + +#define NAME_SESSMGR "SESSMGR " +#define NAME_KEYBOARD "KEYBOARD" +#define NAME_COPY "COPY " +#define NAME_OIAM "OIAM " + + +/* + * Name Resolution is specified in AH. + */ + +#define NAME_RESOLUTION 0x81 + +#if defined(unix) +/* + * In unix, we offer a service to allow the application to keep from + * having to poll us constantly. + */ +#define PS_OR_OIA_MODIFIED 0x99 + +#endif /* defined(unix) */ + +/* + * Codes specified in AL for various services. + */ + +#define QUERY_SESSION_ID 0x01 +#define QUERY_SESSION_PARAMETERS 0x02 +#define QUERY_SESSION_CURSOR 0x0b + +#define CONNECT_TO_KEYBOARD 0x01 +#define DISCONNECT_FROM_KEYBOARD 0x02 +#define WRITE_KEYSTROKE 0x04 +#define DISABLE_INPUT 0x05 +#define ENABLE_INPUT 0x06 + +#define COPY_STRING 0x01 + +#define READ_OIA_GROUP 0x02 + +/* + * For each service, we define the assoicated parameter blocks. + */ + +/* + * Supervisor Services + */ + +typedef struct { + char gate_name[8]; +} NameResolveParms; + + +/* + * Session Information Services + */ + +typedef struct { + char + short_name, + type, + session_id, + reserved, + long_name[8]; +} NameArrayElement; + +typedef struct { + unsigned char + length, + number_matching_session; + NameArrayElement + name_array_element; /* Variable number */ +} NameArray; + +typedef struct { + char + rc, + function_id, + option_code, + data_code; + NameArray far + *name_array; + char + long_name[8]; +} QuerySessionIdParms; + +#define ID_OPTION_BY_NAME 0x01 /* By short (or long) name */ +#define ID_OPTION_ALL 0x00 /* All (of specified type */ + +typedef struct { + char + rc, + function_id, + session_id, + reserved, + session_type, + session_characteristics, + rows, + columns; + char far + *presentation_space; +} QuerySessionParametersParms; + +#define TYPE_WSCTL 0x01 /* Work Station Control */ +#define TYPE_DFT 0x02 /* DFT Host Session */ +#define TYPE_CUT 0x03 /* CUT Host Session */ +#define TYPE_NOTEPAD 0x04 /* Notepad Session */ +#define TYPE_PC 0x05 /* Personal Computer Session */ + +#define CHARACTERISTIC_EAB 0x80 /* Extended Attribute Buffer */ +#define CHARACTERISTIC_PSS 0x40 /* Program Symbols Supported */ + +typedef struct { + char + rc, + function_id, + session_id, + cursor_type, + row_address, /* from 0 */ + column_address; /* from 0 */ +} QuerySessionCursorParms; + +#define CURSOR_INHIBITED_AUTOSCROLL 0x10 +#define CURSOR_INHIBITED 0x04 +#define CURSOR_BLINKING 0x02 +#define CURSOR_BOX 0x01 +typedef struct { + char + rc, + function_id, + session_id, + reserved; + short + event_queue_id, + input_queue_id; + char + intercept_options, + first_connection_identifier; +} ConnectToKeyboardParms; + +typedef struct { + char + rc, + function_id, + session_id, + reserved; + short + connectors_task_id; +} DisconnectFromKeyboardParms; + +typedef struct { + unsigned char + scancode, + shift_state; +} KeystrokeEntry; + +typedef struct { + short + length; /* Length (in bytes) of list */ + KeystrokeEntry keystrokes; /* Variable size */ +} KeystrokeList; + +typedef struct { + char + rc, + function_id, + session_id, + reserved; + short + connectors_task_id; + char + options, + number_of_keys_sent; + union { + KeystrokeEntry + keystroke_entry; + KeystrokeList far + *keystroke_list; + } keystroke_specifier; +} WriteKeystrokeParms; + +#define OPTION_SINGLE_KEYSTROKE 0x20 +#define OPTION_MULTIPLE_KEYSTROKES 0x30 + +typedef struct { + char + rc, + function_id, + session_id, + reserved; + short + connectors_task_id; +} DisableInputParms; + +typedef DisableInputParms EnableInputParms; + +typedef struct { + char + session_id, + reserved; + char far + *buffer; + char + characteristics, + session_type; + short + begin; /* Offset within buffer */ +} BufferDescriptor; + +typedef struct { + char + rc, + function_id; + BufferDescriptor + source; + short + source_end; /* Offset within source buffer */ + BufferDescriptor + target; + char + copy_mode, + reserved; +} CopyStringParms; + +#define COPY_MODE_7_COLOR 0x80 /* Else 4 color mode */ +#define COPY_MODE_FIELD_ATTRIBUTES 0x40 /* Else don't copy attributes */ + +typedef struct { + char + rc, + function_id, + session_id, + reserved; + char far + *oia_buffer; + char + oia_group_number; +} ReadOiaGroupParms; + +/* If the user wants all groups, we return API_OIA_BYTES_ALL_GROUPS bytes */ +#define API_OIA_ALL_GROUPS '\377' +#define API_OIA_BYTES_ALL_GROUPS 22 /* 22 bytes of data */ + +/* API_OIA_INPUT_INHIBITED is special. It returns more than on byte of data */ +#define API_OIA_INPUT_INHIBITED 8 + +#define API_OIA_LAST_LEGAL_GROUP 18 /* Highest legal number */ + + + +#if defined(MSDOS) + +#if !defined(FP_SEG) +#include +#endif /* !defined(FP_SEG) */ + +#else /* defined(MSDOS) */ + +/* + * These definitions are here to provide the descriptions of + * some registers which are, normally, defined in on + * a dos system. + */ + +#define FP_SEG(x) ((unsigned int)(((unsigned long)(x))>>16)) +#define FP_OFF(y) ((unsigned int)(((unsigned long)(y))&0xFFFF)) + +/* + * Undo the preceeding. + */ + +#define SEG_OFF_BACK(x,y) (((x)<<16)|(y)) + +/* + * Now, it is somewhat of a pain, but we need to keep + * 8086 conventions about which of the "highlow"'s map + * into which of the "words". + */ + +#include /* Get ENDIAN from machine/endian.h */ + +/* Determine endian'ess (if necessary) */ + +#if !(defined(BYTE_ORDER) && defined(BIG_ENDIAN)) +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ + +#if defined(vax) || defined(ns32000) || defined(i386) || (defined(mips)&&defined(MIPSEL)) +#define BYTE_ORDER LITTLE_ENDIAN +#endif /* defined(vax) || defined(ns32000) */ + +#if defined(sun) || defined(tahoe) || defined(ibm032) || defined(pyr) || defined(gould) || (defined(mips)&&defined(MIPSEB)) +#define BYTE_ORDER BIG_ENDIAN +#endif /* defined(sun) || defined(tahoe) || defined(ibm032) || defined(pyr) || defined(gould) */ + +#endif /* !(defined(BYTE_ORDER) && defined(BIG_ENDIAN)) */ + +struct highlow { + unsigned char +#if BYTE_ORDER == LITTLE_ENDIAN + al, + ah, + bl, + bh, + cl, + ch, + dl, + dh; +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +#if BYTE_ORDER == BIG_ENDIAN + ah, + al, + bh, + bl, + ch, + cl, + dh, + dl; +#endif /* BYTE_ORDER == BIG_ENDIAN */ +}; + +struct words { + unsigned short + ax, + bx, + cx, + dx; + unsigned short + si, + di; +}; + +union REGS { + struct highlow h; + struct words x; +}; + +struct SREGS { + unsigned short + cs, + ds, + es, + ss; +}; +#endif /* defined(MSDOS) (else section) */ diff --git a/usr.bin/tn3270/ctlr/declare.h b/usr.bin/tn3270/ctlr/declare.h new file mode 100644 index 0000000..0400b33 --- /dev/null +++ b/usr.bin/tn3270/ctlr/declare.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)declare.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Declarations of routines from the controller. + */ + +extern void + AddHost(), + DoReadModified(), + DoReadBuffer(), + OptInit(), + SendToIBM(), + SendTransparent(); + +extern int + DataFrom3270(), + DataFromNetwork(), + OptOrder(), + OutputClock, + TransparentClock; diff --git a/usr.bin/tn3270/ctlr/externs.h b/usr.bin/tn3270/ctlr/externs.h new file mode 100644 index 0000000..11c983c --- /dev/null +++ b/usr.bin/tn3270/ctlr/externs.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)externs.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * External references from the controller. + */ + +#if !defined(MSDOS) +extern char *access_api(); +extern void movetous(), movetothem(), unaccess_api(); +#endif /* !defined(MSDOS) */ + +extern unsigned char + *memNSchr(); /* Search for a character ANDED, increment by stride */ + +extern int + DataToNetwork(), + OutputClock, + suspend(), + TransparentClock, + UnLocked; /* keyboard is UnLocked? */ + +extern void + command(), + ConnectScreen(), + ExitString(), + init_inbound(), + LocalClearScreen(), + RefreshScreen(), + RingBell(), + setconnmode(), + StopScreen(), + TransOut(), + TransStop(); diff --git a/usr.bin/tn3270/ctlr/function.c b/usr.bin/tn3270/ctlr/function.c new file mode 100644 index 0000000..1844860 --- /dev/null +++ b/usr.bin/tn3270/ctlr/function.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)function.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This file, which never produces a function.o, is used solely to + * be run through the preprocessor. + * + * On a 4.3 system (or even msdos), "cc -E function.h" would produce + * the correct output. Unfortunately, 4.2 compilers aren't quite that + * useful. + */ + +#include "function.h" diff --git a/usr.bin/tn3270/ctlr/function.h b/usr.bin/tn3270/ctlr/function.h new file mode 100644 index 0000000..a62018d --- /dev/null +++ b/usr.bin/tn3270/ctlr/function.h @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)function.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * The following are the various functions which the keyboard can ask + * the controller to perform. + * + * Note that this file (the following entries) are scanned by mkhit.c, + * and that the format must remain more-or-less consistent + * [ \t]*TOKEN + */ + +enum ctlrfcn { + + undefined = 0, /* Not yet touched */ + + FCN_NULL, /* Illegal sequence */ + + FCN_RESET, /* unlock keyboard */ + FCN_MAKE_SHIFT_LOCK, + FCN_BREAK_SHIFT_LOCK, + + FCN_MAKE_SHIFT, /* shift key pressed DOWN */ + FCN_BREAK_SHIFT, /* shift key released */ + + FCN_MAKE_ALT, /* alt key pressed DOWN */ + FCN_BREAK_ALT, /* alt key released */ + + FCN_MAKE_CTRL, + + FCN_CAPS_LOCK, + + FCN_MONOCASE, /* DISPLAY in upper case */ + FCN_DVCNL, + + FCN_CHARACTER, /* Not one of the following, but ... */ + FCN_VERTICAL_BAR, /* EBCDIC solid vertical bar */ + FCN_CENTSIGN, /* EBCDIC cent sign */ + FCN_SPACE, /* EBCDIC space */ + FCN_DP, /* EBCDIC dup character */ + FCN_FM, /* EBCDIC field mark */ + + FCN_AID, /* Some AID key */ + FCN_ATTN, + FCN_CURSEL, /* Cursor select function (and aid) */ + FCN_TEST, /* Test function */ + + FCN_EINP, /* erase input (dangerous) */ + FCN_EEOF, + FCN_DELETE, + FCN_INSRT, + FCN_TAB, + FCN_BTAB, + FCN_NL, + FCN_HOME, + FCN_UP, + FCN_DOWN, + FCN_RIGHT, + FCN_LEFT, + FCN_LEFT2, + FCN_RIGHT2, + +#if !defined(PURE3274) + /* + * Local editing functions + */ + FCN_SETTAB, /* set a column tab */ + FCN_DELTAB, + FCN_COLTAB, + FCN_COLBAK, + FCN_INDENT, /* more margin over one col tab */ + FCN_UNDENT, + FCN_SETMRG, + FCN_SETHOM, + FCN_CLRTAB, + FCN_ERASE, /* erase last character */ + FCN_WERASE, + FCN_FERASE, + FCN_WORDTAB, /* tab to start of next word */ + FCN_WORDBACKTAB, + FCN_WORDEND, /* find next end of word */ + FCN_FIELDEND, /* find next end of field */ + + /* + * APL functions + */ + FCN_APLON, /* start using apl character set */ + FCN_APLOFF, + FCN_APLEND, + + FCN_PCON, + FCN_PCOFF, + FCN_INIT, /* re-init screen */ + FCN_SYNCH, /* synch up after line/control error */ + FCN_FLINP, /* flush input buffer */ + FCN_RESHOW, /* redraw screen */ + FCN_MASTER_RESET, /* FLINP, RESET, RESHOW, + more */ + + FCN_DISC, /* suspend application */ + FCN_ESCAPE, /* enter command mode */ + + FCN_ALTK, /* Dvorak keyboard */ + + FCN_XOFF, /* suspend output to screen */ + FCN_XON, /* resume output to screen */ + + FCN_LPRT /* print screen on printer */ +#endif /* !defined(PURE3274) */ +}; +/* + * The following is the structure which defines what a 3270 keystroke + * can do. + */ + +struct hits { + unsigned char keynumber; + struct hit { + enum ctlrfcn ctlrfcn; + unsigned char code; /* AID value or 3270 display code */ + } hit[4]; /* plain, shifted, alted, shiftalted */ +}; + +extern struct hits hits[]; + +/* + * Definitions of the shift state (and the left/right shift key position). + */ + +#define SHIFT_RIGHT 0x20 /* Right shift key is down */ +#define SHIFT_LEFT 0x10 /* Left shift key is down */ +#define SHIFT_CONTROL 0x08 /* Control shift state (unused) */ +#define SHIFT_ALT 0x04 /* ALT shift state */ +#define SHIFT_CAPS 0x02 /* Caps lock state */ +#define SHIFT_UPSHIFT 0x01 /* Upshift state */ diff --git a/usr.bin/tn3270/ctlr/hostctlr.h b/usr.bin/tn3270/ctlr/hostctlr.h new file mode 100644 index 0000000..086d7ee --- /dev/null +++ b/usr.bin/tn3270/ctlr/hostctlr.h @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)hostctlr.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_HOST3270 + +/* define orders given to 3270's */ + +#define ORDER_SF 0x1d /* Start Field */ +#define ORDER_SFE 0x29 /* Start Field Extended */ +#define ORDER_SBA 0x11 /* Set Buffer Address (for output) */ +#define ORDER_SA 0x28 /* Set Attribute */ +#define ORDER_MF 0x2c /* Modify field */ +#define ORDER_IC 0x13 /* Insert Cursor (at buffer address) */ +#define ORDER_PT 0x05 /* Program Tab (absurdly complicated) */ +#define ORDER_RA 0x3c /* Repeat next character to some addr */ +#define ORDER_EUA 0x12 /* Null out every unprotected field + * to some address. + */ +#define ORDER_GE 0x08 /* Graphics Escape */ +#define ORDER_YALE 0x2b /* This is a special YALE order, which + * introduces YALE extended orders + * (like setting tabs, etc.). + */ + +/* The following is defined for initialization and error messages. */ + +struct orders_def { + int + code; /* As in 3270 data stream */ + char + *short_name, /* Short name */ + *long_name; /* Long name */ +}; + +#define ORDERS_DEF { \ + ORDER_SF, "SF", "Start Field", \ + ORDER_SFE, "SFE", "Start Field Extended", \ + ORDER_SBA, "SBA", "Set Buffer Address", \ + ORDER_SA, "SA", "Set Attribute", \ + ORDER_MF, "MF", "Modify Field", \ + ORDER_IC, "IC", "Insert Cursor", \ + ORDER_PT, "PT", "Program Tab", \ + ORDER_RA, "RA", "Repeat to Address", \ + ORDER_EUA, "EUA", "Erase Unprotected to Address", \ + ORDER_GE, "GE", "Graphics Escape", \ + ORDER_YALE, "YALE", "Yale Order" \ + } + + +#define ATTR_RESET 0x00 /* SA only - reset to default */ +# define ATTR_DEFAULT 0x00 /* reset to default */ + /* Also for 0x41-43 below */ +#define ATTR_FIELD 0xC0 /* Field attributes */ +# define ATTR_MASK 0xc0 /* control bits */ +# define ATTR_PROT 0x20 /* protected bit */ +# define ATTR_NUMERIC 0x10 /* numeric field */ +# define ATTR_AUTO_SKIP_MASK 0x30 /* mask to check auto skip */ +# define ATTR_AUTO_SKIP_VALUE 0x30 /* value to have auto skip */ +# define ATTR_DSPD_MASK 0x0c /* highlighting, etc. */ +# define ATTR_DSPD_DNSPD 0x00 /* display, no select */ +# define ATTR_DSPD_DSPD 0x04 /* display, select */ +# define ATTR_DSPD_HIGH 0x08 /* highlighted, select */ +# define ATTR_DSPD_NONDISPLAY 0x0c /* non-display, no select */ +# define ATTR_MDT 0x01 /* modified data tag */ + +#define ATTR_EXTENDED_HIGHLIGHT 0x41 /* Extended highlighting */ +# define ATTR_BLINK 0xf1 /* Blinking */ +# define ATTR_REVERSE_VIDEO 0xf2 /* Reverse video */ +# define ATTR_UNDERSCORE 0xf3 /* Underline */ +#define ATTR_COLOR 0x42 /* Color */ +# define ATTR_BLUE 0xf1 +# define ATTR_RED 0xf2 +# define ATTR_PINK 0xf3 +# define ATTR_GREEN 0xf4 +# define ATTR_TURQUOISE 0xf5 +# define ATTR_YELLOW 0xf6 +# define ATTR_WHITE 0xf7 /* for 3279; black for 3287; */ + /* multicolor for triple */ + /* plane symbol */ +#define ATTR_PROGRAMMED_SYMBOLS 0x43 /* Programmed Symbols */ +# define ATTR_SYMBOL_SET_LOW 0x40 /* Lowest loadable set ID */ +# define ATTR_SYMBOL_SET_HIGH 0xef /* Highest loadable set ID */ +# define ATTR_SYMBOL_SET_APLTEXT 0xf1 + +/* Non-SNA control unit commands */ + +#define CMD_ERASE_ALL_UNPROTECTED 0x0f +#define CMD_ERASE_WRITE 0x05 +#define CMD_ERASE_WRITE_ALTERNATE 0x0d +#define CMD_READ_BUFFER 0x02 +#define CMD_READ_MODIFIED 0x06 +#define CMD_WRITE 0x01 +#define CMD_WRITE_STRUCTURED_FIELD 0x11 + +/* SNA control unit commands */ + +#define CMD_SNA_COPY 0xf7 +#define CMD_SNA_ERASE_ALL_UNPROTECTED 0x6f +#define CMD_SNA_ERASE_WRITE 0xf5 +#define CMD_SNA_ERASE_WRITE_ALTERNATE 0x7e +#define CMD_SNA_READ_BUFFER 0xf2 +#define CMD_SNA_READ_MODIFIED 0xf6 +#define CMD_SNA_READ_MODIFIED_ALL 0x6e +#define CMD_SNA_WRITE 0xf1 +#define CMD_SNA_WRITE_STRUCTURED_FIELD 0xf3 + + +#define WCC_RESET 0x40 +#define WCC_ALARM 0x04 +#define WCC_RESTORE 0x02 +#define WCC_RESET_MDT 0x01 + + +/* Special EBCDIC characters unique to a 3270 */ + +#define EBCDIC_BLANK 0x40 /* Space */ +#define EBCDIC_CENTSIGN 0x4a /* Cent sign */ +#define EBCDIC_DUP 0x1c /* DUP character */ +#define EBCDIC_FM 0x1e /* Field mark character */ +#define EBCDIC_PERCENT 0x6c /* Percent sign */ +#define EBCDIC_SLASH 0x61 /* Slash */ +#define EBCDIC_SOH 0x01 /* Start of Heading */ +#define EBCDIC_STX 0x02 /* Start of Text */ + +/* Structured field types */ +#define SF_3270DS 0x40 /* For write operations */ +#define SF_LPS 0x06 /* Load Programmed Symbols */ +#define SF_SRM 0x09 /* Set Reply Mode */ +#define SF_SWO 0x0b /* Set Window Origin */ +#define SF_READ_PARTITION 0x01 /* Read Partition (Query) */ +#define SF_ERASE_RESET 0x03 /* Erase (and/or Reset) */ +#define SF_SCS_DATA 0x41 /* SCS Data */ +#define SF_CREATE_PARTITION 0x0c /* Create a partition */ + +/* AID characters sent to host. + * + * Note that this file (the following entries) are scanned by mkhit.c, + * and that the format must remain more-or-less consistent + * (#define\tAID_name\t[\t]*TOKEN) + */ + +#define AID_NONE 0x60 /* No AID (display) */ +#define AID_NONE_PRINTER 0xe8 /* No AID (printer) */ + +#define AID_PA1 0x6c +#define AID_PA2 0x6e +#define AID_PA3 0x6b +#define AID_CLEAR 0x6d +#define AID_TREQ 0xf0 +#define AID_ENTER 0x7d +#define AID_SELPEN 0x7e /* + * Really, only SELPEN with DESIGNATOR + * = space or null + */ +#define AID_PF1 0xf1 +#define AID_PF2 0xf2 +#define AID_PF3 0xf3 +#define AID_PF4 0xf4 +#define AID_PF5 0xf5 +#define AID_PF6 0xf6 +#define AID_PF7 0xf7 +#define AID_PF8 0xf8 +#define AID_PF9 0xf9 +#define AID_PF10 0x7a +#define AID_PF11 0x7b +#define AID_PF12 0x7c +#define AID_PF13 0xc1 +#define AID_PF14 0xc2 +#define AID_PF15 0xc3 +#define AID_PF16 0xc4 +#define AID_PF17 0xc5 +#define AID_PF18 0xc6 +#define AID_PF19 0xc7 +#define AID_PF20 0xc8 +#define AID_PF21 0xc9 +#define AID_PF22 0x4a +#define AID_PF23 0x4b +#define AID_PF24 0x4c +#define AID_PF25 0xd1 +#define AID_PF26 0xd2 +#define AID_PF27 0xd3 +#define AID_PF28 0xd4 +#define AID_PF29 0xd5 +#define AID_PF30 0xd6 +#define AID_PF31 0xd7 +#define AID_PF32 0xd8 +#define AID_PF33 0xd9 +#define AID_PF34 0x5a +#define AID_PF35 0x5b +#define AID_PF36 0x5c diff --git a/usr.bin/tn3270/ctlr/inbound.c b/usr.bin/tn3270/ctlr/inbound.c new file mode 100644 index 0000000..fe8d142 --- /dev/null +++ b/usr.bin/tn3270/ctlr/inbound.c @@ -0,0 +1,1194 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)inbound.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include "../general/general.h" +#include "function.h" +#include "hostctlr.h" +#include "oia.h" +#include "scrnctlr.h" +#include "screen.h" +#include "options.h" +#include "../api/dctype.h" +#include "../api/ebc_disp.h" + +#include "../general/globals.h" +#include "externs.h" +#include "declare.h" + +#define EmptyChar() (ourPTail == ourPHead) +#define FullChar() (ourPHead == ourBuffer+sizeof ourBuffer) + + +/* + * We define something to allow us to to IsProtected() quickly + * on unformatted screens (with the current algorithm for fields, + * unprotected takes exponential time...). + * + * The idea is to call SetXIsProtected() BEFORE the + * loop, then use XIsProtected(). + */ + +#define SetXIsProtected() (XWasSF = 1) +#define XIsProtected(p) (IsStartField(p)? \ + XWasSF = 1 : \ + (XWasSF? \ + (XWasSF = 0, XProtected = IsProtected(p)) : \ + XProtected)) + +static char ourBuffer[400]; + +static char *ourPHead = ourBuffer, + *ourPTail = ourBuffer; + +static int HadAid; /* Had an AID haven't sent */ + +static int InsertMode; /* is the terminal in insert mode? */ + +static unsigned int + rememberedshiftstate; /* Shift (alt) state of terminal */ + +# define HITNUM(s) ((((s)&(SHIFT_CAPS|SHIFT_UPSHIFT))? 1:0) \ + + ((((s)&SHIFT_ALT)? 1:0)<<1)) + +static int XWasSF, XProtected; /* For optimizations */ +#if !defined(PURE3274) +extern int TransparentClock, OutputClock; +#endif /* !defined(PURE3274) */ + +#include "kbd.out" /* Get keyboard mapping function */ + +/* the following are global variables */ + +extern int UnLocked; /* keyboard is UnLocked? */ + + +/* + * init_inbound : + * + * Reset variables to initial state. + */ + +void +init_inbound() +{ + ourPHead = ourPTail = ourBuffer; + HadAid = 0; + rememberedshiftstate = 0; + InsertMode = 0; +} + + +/* Tab() - sets cursor to the start of the next unprotected field */ +static void +Tab() +{ + register int i, j; + + i = CursorAddress; + j = WhereAttrByte(CursorAddress); + do { + if (IsStartField(i) && IsUnProtected(ScreenInc(i))) { + break; + } + i = FieldInc(i); + } while (i != j); + if (IsStartField(i) && IsUnProtected(ScreenInc(i))) { + CursorAddress = ScreenInc(i); + } else { + CursorAddress = SetBufferAddress(0,0); + } +} + + +/* BackTab() - sets cursor to the start of the most recent field */ + +static void +BackTab() +{ + register int i; + + i = ScreenDec(CursorAddress); + for (;;) { + if (IsStartField(ScreenDec(i)) && IsUnProtected(i)) { + CursorAddress = i; + break; + } + if (i == CursorAddress) { + CursorAddress = SetBufferAddress(0,0); + break; + } + i = ScreenDec(i); + } +} + +/* + * ModifyMdt() - Turn a modified data tag bit on or off (watch + * out for unformatted screens). + */ + +ModifyMdt(x,on) +int x; +int on; +{ + int i = x; + + if (IsStartField(i)) { /* If we are at a start field position... */ + if (on) { + ModifyHost(i, |= ATTR_MDT); /* Turn it on */ + } else { + ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */ + } + } else { + i = WhereAttrByte(i); /* Find beginning of field */ + if (IsStartField(i)) { /* Is there one? */ + if (on) { + ModifyHost(i, |= ATTR_MDT); /* Turn it on */ + } else { + ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */ + } + } /* else, don't modify - this is an unformatted screen */ + } +} + + +/* EraseEndOfField - erase all characters to the end of a field */ + +static void +EraseEndOfField() +{ + register int i; + + if (IsProtected(CursorAddress)) { + RingBell("Protected Field"); + } else { + TurnOnMdt(CursorAddress); + if (FormattedScreen()) { + i = CursorAddress; + do { + AddHost(i, 0); + i = ScreenInc(i); + } while ((i != CursorAddress) && !IsStartField(i)); + } else { /* Screen is Unformatted */ + i = CursorAddress; + do { + AddHost(i, 0); + i = ScreenInc(i); + } while (i != HighestScreen()); + } + } +} + +/* Delete() - deletes a character from the screen + * + * What we want to do is delete the section + * [where, from-1] from the screen, + * filling in with what comes at from. + * + * The deleting continues to the end of the field (or + * until the cursor wraps). + * + * From can be a start of a field. We + * check for that. However, there can't be any + * fields that start between where and from. + * We don't check for that. + * + * Also, we assume that the protection status of + * everything has been checked by the caller. + * + */ + +static void +Delete(where, from) +register int where, /* Where to start deleting from */ + from; /* Where to pull back from */ +{ + register int i; + + TurnOnMdt(where); /* Only do this once in this field */ + i = where; + do { + if (IsStartField(from)) { + AddHost(i, 0); /* Stick the edge at the start field */ + } else { + AddHost(i, (char)GetHost(from)); + from = ScreenInc(from); /* Move the edge */ + } + i = ScreenInc(i); + } while ((!IsStartField(i)) && (i != where)); +} + +static void +ColBak() +{ + register int i; + + i = ScreenLineOffset(CursorAddress); + for (i = i-1; i >= 0; i--) { + if (OptColTabs[i]) { + break; + } + } + if (i < 0) { + i = 0; + } + CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i); +} + +static void +ColTab() +{ + register int i; + + i = ScreenLineOffset(CursorAddress); + for (i = i+1; i < NumberColumns; i++) { + if (OptColTabs[i]) { + break; + } + } + if (i >= NumberColumns) { + i = NumberColumns-1; + } + CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i); +} + +static void +Home() +{ + register int i; + register int j; + + i = SetBufferAddress(OptHome, 0); + j = WhereLowByte(i); + /* + * If the initial value of i points to the field attribute of + * an unprotected field, we need to return the address of the + * first data byte in the field (assuming there are any!). + */ + if (IsStartField(i) && IsUnProtected(j)) { + CursorAddress = j; + return; + } + do { + if (IsUnProtected(i)) { + CursorAddress = i; + return; + } + /* the following could be a problem if we got here with an + * unformatted screen. However, this is "impossible", since + * with an unformatted screen, the IsUnProtected(i) above + * should be true. + */ + i = ScreenInc(FieldInc(i)); + } while (i != j); + CursorAddress = LowestScreen(); +} + +static +LastOfField(i) +register int i; /* position to start from */ +{ + register int j; + register int k; + + k = j = i; + SetXIsProtected(); + while (XIsProtected(i) || Disspace(GetHost(i))) { + i = ScreenInc(i); + if (i == j) { + break; + } + } + /* We are now IN a word IN an unprotected field (or wrapped) */ + while (!XIsProtected(i)) { + if (!Disspace(GetHost(i))) { + k = i; + } + i = ScreenInc(i); + if (i == j) { + break; + } + } + return(k); +} + + +static void +FlushChar() +{ + ourPTail = ourPHead = ourBuffer; +} + + +/* + * Add one EBCDIC (NOT display code) character to the buffer. + */ + +static void +AddChar(character) +char character; +{ + if (FullChar()) { + ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 0); + if (EmptyChar()) { + FlushChar(); + } else { + char buffer[100]; + + sprintf(buffer, "File %s, line %d: No room in network buffer!\n", + __FILE__, __LINE__); + ExitString(buffer, 1); + /*NOTREACHED*/ + } + } + *ourPHead++ = character; +} + + +static void +SendUnformatted() +{ + register int i, j; + register int Nulls; + register int c; + + /* look for start of field */ + Nulls = 0; + i = j = LowestScreen(); + do { + c = GetHost(i); + if (c == 0) { + Nulls++; + } else { + while (Nulls) { + Nulls--; + AddChar(EBCDIC_BLANK); /* put in blanks */ + } + AddChar((char)disp_ebc[c]); + } + i = ScreenInc(i); + } while (i != j); +} + +static +SendField(i, cmd) +register int i; /* where we saw MDT bit */ +int cmd; /* The command code (type of read) */ +{ + register int j; + register int k; + register int Nulls; + register int c; + + /* look for start of field */ + i = j = WhereLowByte(i); + + /* On a test_request_read, don't send sba and address */ + if ((AidByte != AID_TREQ) + || (cmd == CMD_SNA_READ_MODIFIED_ALL)) { + AddChar(ORDER_SBA); /* set start field */ + AddChar(BufferTo3270_0(j)); /* set address of this field */ + AddChar(BufferTo3270_1(j)); + } + /* + * Only on read_modified_all do we return the contents + * of the field when the attention was caused by a + * selector pen. + */ + if ((AidByte != AID_SELPEN) + || (cmd == CMD_SNA_READ_MODIFIED_ALL)) { + if (!IsStartField(j)) { + Nulls = 0; + k = ScreenInc(WhereHighByte(j)); + do { + c = GetHost(j); + if (c == 0) { + Nulls++; + } else { + while (Nulls) { + Nulls--; + AddChar(EBCDIC_BLANK); /* put in blanks */ + } + AddChar((char)disp_ebc[c]); + } + j = ScreenInc(j); + } while ((j != k) && (j != i)); + } + } else { + j = FieldInc(j); + } + return(j); +} + +/* Various types of reads... */ +void +DoReadModified(cmd) +int cmd; /* The command sent */ +{ + register int i, j; + + if (AidByte) { + if (AidByte != AID_TREQ) { + AddChar(AidByte); + } else { + /* Test Request Read header */ + AddChar(EBCDIC_SOH); + AddChar(EBCDIC_PERCENT); + AddChar(EBCDIC_SLASH); + AddChar(EBCDIC_STX); + } + } else { + AddChar(AID_NONE); + } + if (((AidByte != AID_PA1) && (AidByte != AID_PA2) + && (AidByte != AID_PA3) && (AidByte != AID_CLEAR)) + || (cmd == CMD_SNA_READ_MODIFIED_ALL)) { + if ((AidByte != AID_TREQ) + || (cmd == CMD_SNA_READ_MODIFIED_ALL)) { + /* Test request read_modified doesn't give cursor address */ + AddChar(BufferTo3270_0(CursorAddress)); + AddChar(BufferTo3270_1(CursorAddress)); + } + i = j = WhereAttrByte(LowestScreen()); + /* Is this an unformatted screen? */ + if (!IsStartField(i)) { /* yes, handle separate */ + SendUnformatted(); + } else { + do { + if (HasMdt(i)) { + i = SendField(i, cmd); + } else { + i = FieldInc(i); + } + } while (i != j); + } + } + ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1); + if (EmptyChar()) { + FlushChar(); + HadAid = 0; /* killed that buffer */ + } +} + +/* A read buffer operation... */ + +void +DoReadBuffer() +{ + register int i, j; + + if (AidByte) { + AddChar(AidByte); + } else { + AddChar(AID_NONE); + } + AddChar(BufferTo3270_0(CursorAddress)); + AddChar(BufferTo3270_1(CursorAddress)); + i = j = LowestScreen(); + do { + if (IsStartField(i)) { + AddChar(ORDER_SF); + AddChar(BufferTo3270_1(FieldAttributes(i))); + } else { + AddChar((char)disp_ebc[GetHost(i)]); + } + i = ScreenInc(i); + } while (i != j); + ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1); + if (EmptyChar()) { + FlushChar(); + HadAid = 0; /* killed that buffer */ + } +} + +/* Send some transparent data to the host */ + +void +SendTransparent(buffer, count) +char *buffer; +int count; +{ + char stuff[3]; + + stuff[0] = AID_NONE_PRINTER; + stuff[1] = BufferTo3270_0(count); + stuff[2] = BufferTo3270_1(count); + DataToNetwork(stuff, sizeof stuff, 0); + DataToNetwork(buffer, count, 1); +} + + +/* Try to send some data to host */ + +void +SendToIBM() +{ +#if !defined(PURE3274) + if (TransparentClock >= OutputClock) { + if (HadAid) { + AddChar(AidByte); + HadAid = 0; + } else { + AddChar(AID_NONE_PRINTER); + } + do { + ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1); + } while (!EmptyChar()); + FlushChar(); + } else if (HadAid) { + DoReadModified(CMD_READ_MODIFIED); + } +#else /* !defined(PURE3274) */ + if (HadAid) { + DoReadModified(CMD_READ_MODIFIED); + } +#endif /* !defined(PURE3274) */ +} + +/* This takes in one character from the keyboard and places it on the + * screen. + */ + +static void +OneCharacter(c, insert) +int c; /* character (Ebcdic) to be shoved in */ +int insert; /* are we in insert mode? */ +{ + register int i, j; + + if (IsProtected(CursorAddress)) { + RingBell("Protected Field"); + return; + } + if (insert) { + /* is the last character in the field a blank or null? */ + i = ScreenDec(FieldInc(CursorAddress)); + j = GetHost(i); + if (!Disspace(j)) { + RingBell("No more room for insert"); + return; + } else { + for (j = ScreenDec(i); i != CursorAddress; + j = ScreenDec(j), i = ScreenDec(i)) { + AddHost(i, (char)GetHost(j)); + } + } + } + AddHost(CursorAddress, c); + TurnOnMdt(CursorAddress); + CursorAddress = ScreenInc(CursorAddress); + if (IsStartField(CursorAddress) && + ((FieldAttributes(CursorAddress)&ATTR_AUTO_SKIP_MASK) == + ATTR_AUTO_SKIP_VALUE)) { + Tab(); + } +} + +/* + * AcceptKeystroke() + * + * Processes one keystroke. + * + * Returns: + * + * 0 if this keystroke was NOT processed. + * 1 if everything went OK. + */ + +int +AcceptKeystroke(scancode, shiftstate) +unsigned int + scancode, /* 3270 scancode */ + shiftstate; /* The shift state */ +{ + register int c; + register int i; + register int j; + enum ctlrfcn ctlrfcn; + + if (scancode >= numberof(hits)) { + ExitString( + "Unknown scancode encountered in AcceptKeystroke.\n", 1); + /*NOTREACHED*/ + } + ctlrfcn = hits[scancode].hit[HITNUM(shiftstate)].ctlrfcn; + c = hits[scancode].hit[HITNUM(shiftstate)].code; + + if (!UnLocked || HadAid) { + if (HadAid) { + SendToIBM(); + if (!EmptyChar()) { + return 0; /* nothing to do */ + } + } +#if !defined(PURE3274) + if (!HadAid && EmptyChar()) { + if ((ctlrfcn == FCN_RESET) || (ctlrfcn == FCN_MASTER_RESET)) { + UnLocked = 1; + } + } +#endif /* !defined(PURE3274) */ + if (!UnLocked) { + return 0; + } + } + + /* now, either empty, or haven't seen aid yet */ + +#if !defined(PURE3274) + /* + * If we are in transparent (output) mode, do something special + * with keystrokes. + */ + if (TransparentClock == OutputClock) { + if (ctlrfcn == FCN_AID) { + UnLocked = 0; + InsertMode = 0; + AidByte = (c); + HadAid = 1; + } else { + switch (ctlrfcn) { + case FCN_ESCAPE: + StopScreen(1); + command(0); + if (shell_active == 0) { + ConnectScreen(); + } + break; + + case FCN_RESET: + case FCN_MASTER_RESET: + UnLocked = 1; + break; + + default: + return 0; + } + } + } +#endif /* !defined(PURE3274) */ + + if (ctlrfcn == FCN_CHARACTER) { + /* Add the character to the buffer */ + OneCharacter(c, InsertMode); + } else if (ctlrfcn == FCN_AID) { /* got Aid */ + if (c == AID_CLEAR) { + LocalClearScreen(); /* Side effect is to clear 3270 */ + } + ResetOiaOnlineA(&OperatorInformationArea); + SetOiaTWait(&OperatorInformationArea); + ResetOiaInsert(&OperatorInformationArea); + InsertMode = 0; /* just like a 3278 */ + SetOiaSystemLocked(&OperatorInformationArea); + SetOiaModified(); + UnLocked = 0; + AidByte = c; + HadAid = 1; + SendToIBM(); + } else { + switch (ctlrfcn) { + + case FCN_CURSEL: + c = FieldAttributes(CursorAddress)&ATTR_DSPD_MASK; + if (!FormattedScreen() + || ((c != ATTR_DSPD_DSPD) && (c != ATTR_DSPD_HIGH))) { + RingBell("Cursor not in selectable field"); + } else { + i = ScreenInc(WhereAttrByte(CursorAddress)); + c = GetHost(i); + if (c == DISP_QUESTION) { + AddHost(i, DISP_GREATER_THAN); + TurnOnMdt(i); + } else if (c == DISP_GREATER_THAN) { + AddHost(i, DISP_QUESTION); + TurnOffMdt(i); + } else if (c == DISP_BLANK || c == DISP_NULL + || c == DISP_AMPERSAND) { + UnLocked = 0; + InsertMode = 0; + ResetOiaOnlineA(&OperatorInformationArea); + SetOiaTWait(&OperatorInformationArea); + SetOiaSystemLocked(&OperatorInformationArea); + ResetOiaInsert(&OperatorInformationArea); + SetOiaModified(); + if (c == DISP_AMPERSAND) { + TurnOnMdt(i); /* Only for & type */ + AidByte = AID_ENTER; + } else { + AidByte = AID_SELPEN; + } + HadAid = 1; + SendToIBM(); + } else { + RingBell( + "Cursor not in a selectable field (designator)"); + } + } + break; + +#if !defined(PURE3274) + case FCN_ERASE: + if (IsProtected(ScreenDec(CursorAddress))) { + RingBell("Protected Field"); + } else { + CursorAddress = ScreenDec(CursorAddress); + Delete(CursorAddress, ScreenInc(CursorAddress)); + } + break; + case FCN_WERASE: + j = CursorAddress; + i = ScreenDec(j); + if (IsProtected(i)) { + RingBell("Protected Field"); + } else { + SetXIsProtected(); + while ((!XIsProtected(i) && Disspace(GetHost(i))) + && (i != j)) { + i = ScreenDec(i); + } + /* we are pointing at a character in a word, or + * at a protected position + */ + while ((!XIsProtected(i) && !Disspace(GetHost(i))) + && (i != j)) { + i = ScreenDec(i); + } + /* we are pointing at a space, or at a protected + * position + */ + CursorAddress = ScreenInc(i); + Delete(CursorAddress, j); + } + break; + + case FCN_FERASE: + if (IsProtected(CursorAddress)) { + RingBell("Protected Field"); + } else { + CursorAddress = ScreenInc(CursorAddress); /* for btab */ + BackTab(); + EraseEndOfField(); + } + break; + + case FCN_RESET: + if (InsertMode) { + InsertMode = 0; + ResetOiaInsert(&OperatorInformationArea); + SetOiaModified(); + } + break; + case FCN_MASTER_RESET: + if (InsertMode) { + InsertMode = 0; + ResetOiaInsert(&OperatorInformationArea); + SetOiaModified(); + } + RefreshScreen(); + break; +#endif /* !defined(PURE3274) */ + + case FCN_UP: + CursorAddress = ScreenUp(CursorAddress); + break; + + case FCN_LEFT: + CursorAddress = ScreenDec(CursorAddress); + break; + + case FCN_RIGHT: + CursorAddress = ScreenInc(CursorAddress); + break; + + case FCN_DOWN: + CursorAddress = ScreenDown(CursorAddress); + break; + + case FCN_DELETE: + if (IsProtected(CursorAddress)) { + RingBell("Protected Field"); + } else { + Delete(CursorAddress, ScreenInc(CursorAddress)); + } + break; + + case FCN_INSRT: + InsertMode = !InsertMode; + if (InsertMode) { + SetOiaInsert(&OperatorInformationArea); + } else { + ResetOiaInsert(&OperatorInformationArea); + } + SetOiaModified(); + break; + + case FCN_HOME: + Home(); + break; + + case FCN_NL: + /* The algorithm is to look for the first unprotected + * column after column 0 of the following line. Having + * found that unprotected column, we check whether the + * cursor-address-at-entry is at or to the right of the + * LeftMargin AND the LeftMargin column of the found line + * is unprotected. If this conjunction is true, then + * we set the found pointer to the address of the LeftMargin + * column in the found line. + * Then, we set the cursor address to the found address. + */ + i = SetBufferAddress(ScreenLine(ScreenDown(CursorAddress)), 0); + j = ScreenInc(WhereAttrByte(CursorAddress)); + do { + if (IsUnProtected(i)) { + break; + } + /* Again (see comment in Home()), this COULD be a problem + * with an unformatted screen. + */ + /* If there was a field with only an attribute byte, + * we may be pointing to the attribute byte of the NEXT + * field, so just look at the next byte. + */ + if (IsStartField(i)) { + i = ScreenInc(i); + } else { + i = ScreenInc(FieldInc(i)); + } + } while (i != j); + if (!IsUnProtected(i)) { /* couldn't find unprotected */ + i = SetBufferAddress(0,0); + } + if (OptLeftMargin <= ScreenLineOffset(CursorAddress)) { + if (IsUnProtected(SetBufferAddress(ScreenLine(i), + OptLeftMargin))) { + i = SetBufferAddress(ScreenLine(i), OptLeftMargin); + } + } + CursorAddress = i; + break; + + case FCN_EINP: + if (!FormattedScreen()) { + i = CursorAddress; + TurnOffMdt(i); + do { + AddHost(i, 0); + i = ScreenInc(i); + } while (i != CursorAddress); + } else { + /* + * The algorithm is: go through each unprotected + * field on the screen, clearing it out. When + * we are at the start of a field, skip that field + * if its contents are protected. + */ + i = j = FieldInc(CursorAddress); + do { + if (IsUnProtected(ScreenInc(i))) { + i = ScreenInc(i); + TurnOffMdt(i); + do { + AddHost(i, 0); + i = ScreenInc(i); + } while (!IsStartField(i)); + } else { + i = FieldInc(i); + } + } while (i != j); + } + Home(); + break; + + case FCN_EEOF: + EraseEndOfField(); + break; + + case FCN_SPACE: + OneCharacter(DISP_BLANK, InsertMode); /* Add cent */ + break; + + case FCN_CENTSIGN: + OneCharacter(DISP_CENTSIGN, InsertMode); /* Add cent */ + break; + + case FCN_FM: + OneCharacter(DISP_FM, InsertMode); /* Add field mark */ + break; + + case FCN_DP: + if (IsProtected(CursorAddress)) { + RingBell("Protected Field"); + } else { + OneCharacter(DISP_DUP, InsertMode);/* Add dup character */ + Tab(); + } + break; + + case FCN_TAB: + Tab(); + break; + + case FCN_BTAB: + BackTab(); + break; + +#ifdef NOTUSED /* Actually, this is superseded by unix flow + * control. + */ + case FCN_XOFF: + Flow = 0; /* stop output */ + break; + + case FCN_XON: + if (!Flow) { + Flow = 1; /* turn it back on */ + DoTerminalOutput(); + } + break; +#endif /* NOTUSED */ + +#if !defined(PURE3274) + case FCN_ESCAPE: + /* FlushChar(); do we want to flush characters from before? */ + StopScreen(1); + command(0); + if (shell_active == 0) { + ConnectScreen(); + } + break; + + case FCN_DISC: + StopScreen(1); + suspend(); + setconnmode(); + ConnectScreen(); + break; + + case FCN_RESHOW: + RefreshScreen(); + break; + + case FCN_SETTAB: + OptColTabs[ScreenLineOffset(CursorAddress)] = 1; + break; + + case FCN_DELTAB: + OptColTabs[ScreenLineOffset(CursorAddress)] = 0; + break; + + /* + * Clear all tabs, home line, and left margin. + */ + case FCN_CLRTAB: + for (i = 0; i < sizeof OptColTabs; i++) { + OptColTabs[i] = 0; + } + OptHome = 0; + OptLeftMargin = 0; + break; + + case FCN_COLTAB: + ColTab(); + break; + + case FCN_COLBAK: + ColBak(); + break; + + case FCN_INDENT: + ColTab(); + OptLeftMargin = ScreenLineOffset(CursorAddress); + break; + + case FCN_UNDENT: + ColBak(); + OptLeftMargin = ScreenLineOffset(CursorAddress); + break; + + case FCN_SETMRG: + OptLeftMargin = ScreenLineOffset(CursorAddress); + break; + + case FCN_SETHOM: + OptHome = ScreenLine(CursorAddress); + break; + + /* + * Point to first character of next unprotected word on + * screen. + */ + case FCN_WORDTAB: + i = CursorAddress; + SetXIsProtected(); + while (!XIsProtected(i) && !Disspace(GetHost(i))) { + i = ScreenInc(i); + if (i == CursorAddress) { + break; + } + } + /* i is either protected, a space (blank or null), + * or wrapped + */ + while (XIsProtected(i) || Disspace(GetHost(i))) { + i = ScreenInc(i); + if (i == CursorAddress) { + break; + } + } + CursorAddress = i; + break; + + case FCN_WORDBACKTAB: + i = ScreenDec(CursorAddress); + SetXIsProtected(); + while (XIsProtected(i) || Disspace(GetHost(i))) { + i = ScreenDec(i); + if (i == CursorAddress) { + break; + } + } + /* i is pointing to a character IN an unprotected word + * (or i wrapped) + */ + while (!Disspace(GetHost(i))) { + i = ScreenDec(i); + if (i == CursorAddress) { + break; + } + } + CursorAddress = ScreenInc(i); + break; + + /* Point to last non-blank character of this/next + * unprotected word. + */ + case FCN_WORDEND: + i = ScreenInc(CursorAddress); + SetXIsProtected(); + while (XIsProtected(i) || Disspace(GetHost(i))) { + i = ScreenInc(i); + if (i == CursorAddress) { + break; + } + } + /* we are pointing at a character IN an + * unprotected word (or we wrapped) + */ + while (!Disspace(GetHost(i))) { + i = ScreenInc(i); + if (i == CursorAddress) { + break; + } + } + CursorAddress = ScreenDec(i); + break; + + /* Get to last non-blank of this/next unprotected + * field. + */ + case FCN_FIELDEND: + i = LastOfField(CursorAddress); + if (i != CursorAddress) { + CursorAddress = i; /* We moved; take this */ + } else { + j = FieldInc(CursorAddress); /* Move to next field */ + i = LastOfField(j); + if (i != j) { + CursorAddress = i; /* We moved; take this */ + } + /* else - nowhere else on screen to be; stay here */ + } + break; +#endif /* !defined(PURE3274) */ + + default: + /* We don't handle this yet */ + RingBell("Function not implemented"); + } + } + return 1; /* We did something! */ +} + + +/* + * We get data from the terminal. We keep track of the shift state + * (including ALT, CONTROL), and then call AcceptKeystroke to actually + * process any non-shift keys. + */ + +int +DataFrom3270(buffer, count) +unsigned char *buffer; /* where the data is */ +int count; /* how much data there is */ +{ + int origCount; + + origCount = count; + + while (count) { + if (*buffer >= numberof(hits)) { + ExitString("Unknown scancode encountered in DataFrom3270.\n", 1); + /*NOTREACHED*/ + } + + switch (hits[*buffer].hit[HITNUM(rememberedshiftstate)].ctlrfcn) { + + case FCN_MAKE_SHIFT: + rememberedshiftstate |= (SHIFT_RIGHT|SHIFT_UPSHIFT); + break; + case FCN_BREAK_SHIFT: + rememberedshiftstate &= ~(SHIFT_RIGHT|SHIFT_UPSHIFT); + break; + case FCN_MAKE_ALT: + rememberedshiftstate |= SHIFT_ALT; + break; + case FCN_BREAK_ALT: + rememberedshiftstate &= ~SHIFT_ALT; + break; + default: + if (AcceptKeystroke(*buffer, rememberedshiftstate) == 0) { + return(origCount-count); + } + break; + } + buffer++; + count--; + } + return(origCount-count); +} diff --git a/usr.bin/tn3270/ctlr/oia.c b/usr.bin/tn3270/ctlr/oia.c new file mode 100644 index 0000000..1f80359 --- /dev/null +++ b/usr.bin/tn3270/ctlr/oia.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)oia.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Routines to maintain the Operator Information Area. + */ + +#include "../general/general.h" + +#include "oia.h" +#include "../general/globals.h" + + +init_oia() +{ + ClearElement(OperatorInformationArea); +} diff --git a/usr.bin/tn3270/ctlr/oia.h b/usr.bin/tn3270/ctlr/oia.h new file mode 100644 index 0000000..a1414ca --- /dev/null +++ b/usr.bin/tn3270/ctlr/oia.h @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)oia.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This file describes the Operator Information Area in the 3270. + * + * Our OIA looks like that used by the 3270 PC and PC 3270 products. + */ + +#define INCLUDED_OIA + +typedef struct { + char + online_ownership, + character_selection, + shift_state, + pss_group_1, + highlight_group_1, + color_group_1, + insert, + input_inhibited[5], + pss_group_2, + highlight_group_2, + color_group_2, + comm_error_reminder, + printer_status, + reserved_group_14, + reserved_group_15, + autokey_play_record_status, + autokey_abort_pause_status, + enlarge_state; +} OIA; + +/* Bits in online_ownership */ +#define OIA_SETUP 0x80 +#define OIA_TEST 0x40 +#define OIA_SSCP_LU 0x20 +#define OIA_LU_LU 0x10 +#define OIA_UNOWNED 0x08 +#define OIA_SUBSYSTEM_READY 0x04 + +/* Bit in character_selection */ +#define OIA_EXTENDED_SELECT 0x80 +#define OIA_APL 0x40 +#define OIA_KANA 0x20 +#define OIA_ALPHA 0x10 +#define OIA_TEXT 0x08 + +/* Bits in shift_state */ +#define OIA_NUMERIC 0x80 +#define OIA_UPPER_SHIFT 0x40 + +/* Bits in pss_group_1, highlight_group_1, and color_group_1 */ +#define OIA_SELECTABLE 0x80 +#define OIA_FIELD_INHERIT 0x40 + +/* Bits in insert */ +#define OIA_INSERT_MODE 0x80 + +/* We define this to be a 'long' followed by a 'char' (5 bytes) */ + +#define OIA_NON_RESETTABLE 0x80 +#define OIA_SECURITY_KEY 0x40 +#define OIA_MACHINE_CHECK 0x20 +#define OIA_COMM_CHECK 0x10 +#define OIA_PROGRAM_CHECK 0x08 +#define OIA_RETRY 0x04 +#define OIA_DEVICE_NOT_WORKING 0x02 +#define OIA_DEVICE_VERY_BUSY 0x01 + +#define OIA_DEVICE_BUSY 0x80 +#define OIA_TERMINAL_WAIT 0x40 +#define OIA_MINUS_SYMBOL 0x20 +#define OIA_MINUS_FUNCTION 0x10 +#define OIA_TOO_MUCH_ENTERED 0x08 +#define OIA_NOT_ENOUGH_ENTERED 0x04 +#define OIA_WRONG_NUMBER 0x02 +#define OIA_NUMERIC_FIELD 0x01 + +#define OIA_OP_UNAUTHORIZED 0x80 +#define OIA_OP_UNAUTHORIZED_MIN 0x40 +#define OIA_INVALID_DEAD_KEY_COMBO 0x20 +#define OIA_WRONG_PLACE 0x10 + +#define OIA_MESSAGE_PENDING 0x80 +#define OIA_PARTITION_WAIT 0x40 +#define OIA_SYSTEM_WAIT 0x20 +#define OIA_HARDWARE_MISMATCH 0x10 +#define OIA_LOGICAL_TERM_NOT_CONF 0x08 + + +#define OIA_AUTOKEY_INHIBIT 0x80 +#define OIA_API_INHIBIT 0x40 + +/* Bits in pss_group_2 */ +#define OIA_PS_SELECTED 0x80 +#define OIA_PC_DISPLAY_DISABLE 0x40 + +/* Bits in highlight_group_2 and color_group_2 */ +#define OIA_SELECTED 0x80 + +/* Bits in comm_error_reminder */ +#define OIA_COMM_ERROR 0x80 +#define OIA_RTM 0x40 + +/* Bits in printer_status */ +#define OIA_PRINT_NOT_CUSTOM 0x80 +#define OIA_PRINTER_MALFUNCTION 0x40 +#define OIA_PRINTER_PRINTING 0x20 +#define OIA_ASSIGN_PRINTER 0x10 +#define OIA_WHAT_PRINTER 0x08 +#define OIA_PRINTER_ASSIGNMENT 0x04 + +/* Bits in autokey_play_record_status */ +#define OIA_PLAY 0x80 +#define OIA_RECORD 0x40 + +/* Bits in autokey_abort_pause_status */ +#define OIA_RECORDING_OVERFLOW 0x80 +#define OIA_PAUSE 0x40 + +/* Bits in enlarge_state */ +#define OIA_WINDOW_IS_ENLARGED 0x80 + +/* Define functions to set and read the oia */ + +#define SetOiaOnlineA(oia) SetOiaMyJob((oia)) /* Side-effect */ +#define ResetOiaOnlineA(oia) \ + /* Nothing defined for this */ + +#define IsOiaReady3274(oia) ((oia)->online_ownership&OIA_SUBSYSTEM_READY) +#define ResetOiaReady3274(oia) (oia)->online_ownership &= ~OIA_SUBSYSTEM_READY +#define SetOiaReady3274(oia) (oia)->online_ownership |= OIA_SUBSYSTEM_READY + +#define IsOiaMyJob(oia) ((oia)->online_ownership&OIA_LU_LU) +#define ResetOiaMyJob(oia) (oia)->online_ownership &= ~OIA_LU_LU +#define SetOiaMyJob(oia) (oia)->online_ownership |= OIA_LU_LU + +#define IsOiaInsert(oia) ((oia)->online_ownership&OIA_INSERT_MODE) +#define ResetOiaInsert(oia) (oia)->online_ownership &= ~OIA_INSERT_MODE +#define SetOiaInsert(oia) (oia)->online_ownership |= OIA_INSERT_MODE + +#define IsOiaSystemLocked(oia) ((oia)->input_inhibited[3]&OIA_SYSTEM_WAIT) +#define ResetOiaSystemLocked(oia) \ + (oia)->input_inhibited[3] &= ~OIA_SYSTEM_WAIT +#define SetOiaSystemLocked(oia) (oia)->input_inhibited[3] |= OIA_SYSTEM_WAIT + +#define IsOiaTWait(oia) ((oia)->input_inhibited[1]&OIA_TERMINAL_WAIT) +#define ResetOiaTWait(oia) (oia)->input_inhibited[1] &= ~OIA_TERMINAL_WAIT +#define SetOiaTWait(oia) (oia)->input_inhibited[1] |= OIA_TERMINAL_WAIT + +#define IsOiaApiInhibit(oia) ((oia)->input_inhibited[4] & OIA_API_INHIBIT) +#define ResetOiaApiInhibit(oia) ((oia)->input_inhibited[4] &= ~OIA_API_INHIBIT) +#define SetOiaApiInhibit(oia) ((oia)->input_inhibited[4] |= OIA_API_INHIBIT) + +/* A macro to let the world know that someone has modified the OIA. */ +#define SetOiaModified() oia_modified = 1 +#define SetPsModified() ps_modified = 1 diff --git a/usr.bin/tn3270/ctlr/options.c b/usr.bin/tn3270/ctlr/options.c new file mode 100644 index 0000000..38a2d43 --- /dev/null +++ b/usr.bin/tn3270/ctlr/options.c @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)options.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * this file contains the definitions, initialization, and processing of + * commands to handle the various local options (APL ON, etc.) + */ + +#include "options.h" + +#include "../general/globals.h" +#include "declare.h" + +void +OptInit() +{ + register int i; + + OptAPLmode = 0; + OptNullProcessing = 1; /* improved null processing */ + OptZonesMode = 0; /* zones mode off */ + OptEnterNL = 0; /* regular enter/new line keys */ + OptColFieldTab = 0; /* regular column/field tab keys */ + OptPacing = 1; /* do pacing */ + OptAlphaInNumeric = 0; /* allow alpha in numeric fields */ + for (i = 0; i < sizeof OptColTabs; i++) { + OptColTabs[i] = ((i%8) == 0); /* every 8 columns */ + } + OptHome = 0; + OptLeftMargin = 0; + OptWordWrap = 0; +} + +OptOrder(pointer, count, control) +unsigned char *pointer; +int count; +int control; +{ + int i, j, character, origCount; + + origCount = count; + + if (count == 0) { + return(0); + } + character = *pointer&0xff; + pointer++; + count--; + switch (character) { + case 0xa0: + OptAPLmode = 1; + break; + case 0x61: + OptAPLmode = 0; + break; + case 0x95: + OptNullProcessing = 0; + break; + case 0xd5: + OptNullProcessing = 1; + break; + case 0xa9: + OptZonesMode = 1; + break; + case 0xe9: + OptZonesMode = 0; + break; + case 0x85: + OptEnterNL = 1; + break; + case 0xc5: + OptEnterNL = 0; + break; + case 0x83: + OptColFieldTab = 1; + break; + case 0xc3: + OptColFieldTab = 0; + break; + case 0x97: + OptPacing = 0; + break; + case 0xd7: + OptPacing = 1; + break; + case 0xa5: + OptAlphaInNumeric = 1; + break; + case 0xe5: + OptAlphaInNumeric = 0; + break; + case 0xe3: + if (!control && count < 30) { + return(0); /* want more! */ + } + for (i = 0; i < sizeof OptColTabs; i++) { + OptColTabs[i] = 0; + } + if (!count) { + break; + } + j = (*pointer&0xff)-0x40; + count--; + pointer++; + if (j < 0 || j >= 24) { + break; + } + OptHome = j; + if (!count) { + break; + } + j = (*pointer&0xff)-0x40; + count--; + pointer++; + if (j < 0 || j >= 80) { + break; + } + OptLeftMargin = j; + if (!count) { + break; + } + i = count; + if (i > 28) { + i = 28; + } + while (i) { + j = (*pointer&0xff)-0x40; + if (j < 0 || j >= sizeof OptColTabs) { + break; + } + OptColTabs[j] = 1; + i --; + pointer++; + count--; + } + break; + case 0xa6: + OptWordWrap = 1; + break; + case 0xe6: + OptWordWrap = 0; + break; + default: + break; + } + return(origCount - count); +} diff --git a/usr.bin/tn3270/ctlr/options.h b/usr.bin/tn3270/ctlr/options.h new file mode 100644 index 0000000..fbf5b10 --- /dev/null +++ b/usr.bin/tn3270/ctlr/options.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)options.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * the various options that run our life. Very few of these are implemented + * as yet. + */ + +#define INCLUDED_OPTIONS diff --git a/usr.bin/tn3270/ctlr/outbound.c b/usr.bin/tn3270/ctlr/outbound.c new file mode 100644 index 0000000..72432f2 --- /dev/null +++ b/usr.bin/tn3270/ctlr/outbound.c @@ -0,0 +1,605 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)outbound.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include "../general/general.h" + +#include "hostctlr.h" +#include "oia.h" +#include "screen.h" +#include "../api/ebc_disp.h" + +#include "../general/globals.h" +#include "externs.h" +#include "declare.h" + +#define SetHighestLowest(position) { \ + if (position < Lowest) { \ + Lowest = position; \ + } \ + if (position > Highest) { \ + Highest = position; \ + } \ + } + + +static int LastWasTerminated = 1; /* was "control" = 1 last time? */ + +/* some globals */ + +#if !defined(PURE3274) +int OutputClock; /* what time it is */ +int TransparentClock; /* time we were last in transparent */ +#endif /* !defined(PURE3274) */ + +char CIABuffer[64] = { + 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f +}; + +static struct orders_def orders_def[] = ORDERS_DEF; + +/* + * init_ctlr() + * + * Initialize all data from the 'data' portion to their startup values. + */ + +void +init_ctlr() +{ + LastWasTerminated = 1; + init_inbound(); + init_oia(); +} + + +FieldInc(position) +register int position; /* Position in previous field */ +{ + register ScreenImage *ptr; + + ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK, + HighestScreen()-position, ATTR_MASK, sizeof Host[0]); + if (ptr == 0) { + ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK, + position-LowestScreen(), ATTR_MASK, sizeof Host[0]); + if (ptr == 0) { + return LowestScreen(); + } + } + return ptr-Host; +} + +FieldDec(position) +int position; +{ + register ScreenImage *ptr; + + ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK, + position-LowestScreen(), ATTR_MASK, -sizeof Host[0]); + if (ptr == 0) { + ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK, + HighestScreen()-position, ATTR_MASK, -sizeof Host[0]); + if (ptr == 0) { + return LowestScreen(); + } + } + return ptr-Host; +} + +/* Clear3270 - called to clear the screen */ + +void +Clear3270() +{ + ClearArray(Host); + DeleteAllFields(); /* get rid of all fields */ + BufferAddress = SetBufferAddress(0,0); + CursorAddress = SetBufferAddress(0,0); + Lowest = LowestScreen(); + Highest = HighestScreen(); +} + +/* AddHost - called to add a character to the buffer. + * We use a macro in this module, since we call it so + * often from loops. + * + * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or + * anything similar. (I don't define any temporary variables, again + * just for the speed.) + */ +void +AddHost(position, character) +int position; +char character; +{ +# define AddHostA(p,c) \ + { \ + if (IsStartField(p)) { \ + DeleteField(p); \ + Highest = HighestScreen(); \ + Lowest = LowestScreen(); \ + SetHighestLowest(p); \ + } \ + SetHost(p, c); \ + } +# define AddHost(p,c) \ + { \ + if (c != GetHost(p)) { \ + SetHighestLowest(p); \ + } \ + AddHostA(p,c); \ + } /* end of macro of AddHost */ + + AddHost(position, character); +} + +/* returns the number of characters consumed */ +int +DataFromNetwork(Buffer, count, control) +char *Buffer; /* what the data is */ +register int count; /* and how much there is */ +int control; /* this buffer ended block? */ +{ + int origCount; + register unsigned char *buffer = (unsigned char *)Buffer; + register int c; + register int i; + static int Command; + static int Wcc; + + origCount = count; + + /* + * If this is the start of a new data stream, then look + * for an op-code and (possibly) a WCC. + */ + if (LastWasTerminated) { + + if (count < 2) { + if (count == 0) { + ExitString("Short count received from host!\n", 1); + return(count); + } + Command = buffer[0]; + switch (Command) { /* This had better be a read command */ + case CMD_READ_MODIFIED: + case CMD_SNA_READ_MODIFIED: + case CMD_SNA_READ_MODIFIED_ALL: + SetOiaOnlineA(&OperatorInformationArea); + SetOiaModified(); + DoReadModified(Command); + break; + case CMD_READ_BUFFER: + case CMD_SNA_READ_BUFFER: + SetOiaOnlineA(&OperatorInformationArea); + SetOiaModified(); + DoReadBuffer(); + break; + default: + { + char s_buffer[100]; + + sprintf(s_buffer, + "Unexpected read command code 0x%x received.\n", + Command); + ExitString(s_buffer, 1); + break; + } + } + return(1); /* We consumed everything */ + } + Command = buffer[0]; + Wcc = buffer[1]; + if (Wcc & WCC_RESET_MDT) { + i = c = WhereAttrByte(LowestScreen()); + do { + if (HasMdt(i)) { + TurnOffMdt(i); + } + i = FieldInc(i); + } while (i != c); + } + + switch (Command) { + case CMD_ERASE_WRITE: + case CMD_ERASE_WRITE_ALTERNATE: + case CMD_SNA_ERASE_WRITE: + case CMD_SNA_ERASE_WRITE_ALTERNATE: + { + int newlines, newcolumns; + + SetOiaOnlineA(&OperatorInformationArea); + ResetOiaTWait(&OperatorInformationArea); + SetOiaModified(); + if ((Command == CMD_ERASE_WRITE) + || (Command == CMD_SNA_ERASE_WRITE)) { + newlines = 24; + newcolumns = 80; + } else { + newlines = MaxNumberLines; + newcolumns = MaxNumberColumns; + } + if ((newlines != NumberLines) + || (newcolumns != NumberColumns)) { + /* + * The LocalClearScreen() is really for when we + * are going from a larger screen to a smaller + * screen, and we need to clear off the stuff + * at the end of the lines, or the lines at + * the end of the screen. + */ + LocalClearScreen(); + NumberLines = newlines; + NumberColumns = newcolumns; + ScreenSize = NumberLines * NumberColumns; + } + Clear3270(); +#if !defined(PURE3274) + if (TransparentClock == OutputClock) { + TransStop(); + } +#endif /* !defined(PURE3274) */ + break; + } + + case CMD_ERASE_ALL_UNPROTECTED: + case CMD_SNA_ERASE_ALL_UNPROTECTED: + SetOiaOnlineA(&OperatorInformationArea); + ResetOiaTWait(&OperatorInformationArea); + SetOiaModified(); + CursorAddress = HighestScreen()+1; + for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) { + if (IsUnProtected(i)) { + if (CursorAddress > i) { + CursorAddress = i; + } + AddHost(i, '\0'); + } + if (HasMdt(i)) { + TurnOffMdt(i); + } + } + if (CursorAddress == HighestScreen()+1) { + CursorAddress = SetBufferAddress(0,0); + } + UnLocked = 1; + AidByte = 0; + ResetOiaSystemLocked(&OperatorInformationArea); + SetOiaModified(); + TerminalIn(); + break; + case CMD_WRITE: + case CMD_SNA_WRITE: + SetOiaOnlineA(&OperatorInformationArea); + ResetOiaTWait(&OperatorInformationArea); + SetOiaModified(); + break; + default: + { + char s_buffer[100]; + + sprintf(s_buffer, + "Unexpected write command code 0x%x received.\n", + Command); + ExitString(s_buffer, 1); + break; + } + } + + count -= 2; /* strip off command and wcc */ + buffer += 2; + + } else { +#if !defined(PURE3274) + if (TransparentClock == OutputClock) { + TransOut(buffer, count, -1, control); + count = 0; + } +#endif /* !defined(PURE3274) */ + } + LastWasTerminated = 0; /* then, reset at end... */ + + while (count) { + count--; + c = *buffer++; + if (IsOrder(c)) { + /* handle an order */ + switch (c) { +# define Ensure(x) if (count < x) { \ + if (!control) { \ + return(origCount-(count+1)); \ + } else { \ + /* XXX - should not occur */ \ + count = 0; \ + break; \ + } \ + } + case ORDER_SF: + Ensure(1); + c = *buffer++; + count--; + if ( ! (IsStartField(BufferAddress) && + FieldAttributes(BufferAddress) == c)) { + SetHighestLowest(BufferAddress); + NewField(BufferAddress,c); + } + BufferAddress = ScreenInc(BufferAddress); + break; + case ORDER_SBA: + Ensure(2); + i = buffer[0]; + c = buffer[1]; +#if !defined(PURE3274) + /* Check for transparent write */ + if ((i == 0) && ((c == 0) || (c == 1) || (c == 5))) { + TransparentClock = OutputClock+1; + TransOut(buffer+2, count-2, c, control); + buffer += count; + count -= count; + break; + } +#endif /* !defined(PURE3274) */ + BufferAddress = Addr3270(i, c); + buffer += 2; + count -= 2; + break; + case ORDER_IC: + CursorAddress = BufferAddress; + break; + /* + * XXX - PT is supposed to null fill the screen buffer + * under certain draconian conditions. + */ + case ORDER_PT: + i = BufferAddress; + do { + if (IsStartField(i)) { + if (!IsProtected(ScreenInc(i))) { + break; + } + } + i = ScreenInc(i); + } while (i != HighestScreen()); + BufferAddress = ScreenInc(i); + break; + case ORDER_RA: + Ensure(3); + i = Addr3270(buffer[0], buffer[1]); + if ((i < 0) || (i > HighestScreen())) { + char s_buffer[200]; + + sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n", + "Invalid 3270 order 'Repeat to Address' to address ", + i, + "(Screen currently set to ", + NumberLines, + " by ", + NumberColumns, + ".)"); + ExitString(s_buffer, 1); + /*NOTREACHED*/ + } + c = buffer[2]; + if (c == ORDER_GE) { + Ensure(4); + c = buffer[3]; + buffer += 4; + count -= 4; + } else { + buffer += 3; + count -= 3; + } + do { + AddHost(BufferAddress, ebc_disp[c]); + BufferAddress = ScreenInc(BufferAddress); + } while (BufferAddress != i); + break; + case ORDER_EUA: /* (from [here,there), ie: half open interval] */ + Ensure(2); + /* + * Compiler error - msc version 4.0: + * "expression too complicated". + */ + i = WhereAttrByte(BufferAddress); + c = FieldAttributes(i); + i = Addr3270(buffer[0], buffer[1]); + if ((i < 0) || (i > HighestScreen())) { + char s_buffer[200]; + + sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n", + "Invalid 3270 order 'Erase Unprotected to Address' to address ", + i, + "(Screen currently set to ", + NumberLines, + " by ", + NumberColumns, + ".)"); + ExitString(s_buffer, 1); + /*NOTREACHED*/ + } + do { + if (IsStartField(BufferAddress)) { + c = FieldAttributes(BufferAddress); + } else if (!IsProtectedAttr(BufferAddress, c)) { + AddHost(BufferAddress, 0); + } + BufferAddress = ScreenInc(BufferAddress); + } while (i != BufferAddress); + buffer += 2; + count -= 2; + break; + case ORDER_GE: + Ensure(2); + /* XXX Should do SOMETHING! */ + /* XXX buffer += 0; */ + /* XXX count -= 0; *//* For now, just use this character */ + break; + case ORDER_YALE: /* special YALE defined order */ + Ensure(2); /* need at least two characters */ + if (*buffer == 0x5b) { + i = OptOrder(buffer+1, count-1, control); + if (i == 0) { + return(origCount-(count+1)); /* come here again */ + } else { + buffer += 1 + i; + count -= (1 + i); + } + } + break; + default: + { + char s_buffer[100]; + static struct orders_def unk_order + = { 0, "??", "(unknown)" }; + struct orders_def *porder = &unk_order; + int s_i; + + for (s_i = 0; s_i <= highestof(orders_def); s_i++) { + if (orders_def[s_i].code == c) { + porder = &orders_def[s_i]; + break; + } + } + sprintf(s_buffer, + "Unsupported order '%s' (%s, 0x%x) received.\n", + porder->long_name, porder->short_name, c); + ExitString(s_buffer, 1); + /*NOTREACHED*/ + } + } + if (count < 0) { + count = 0; + } + } else { + /* Data comes in large clumps - take it all */ + i = BufferAddress; + AddHostA(i, ebc_disp[c]); + SetHighestLowest(i); + i = ScreenInc(i); + c = *buffer; + while (count && !IsOrder(c)) { + AddHostA(i, ebc_disp[c]); + i = ScreenInc(i); + if (i == LowestScreen()) { + SetHighestLowest(HighestScreen()); + } + count--; + buffer++; + c = *buffer; + } + SetHighestLowest(i); + BufferAddress = i; + } + } + if (count == 0) { + if (control) { +#if !defined(PURE3274) + OutputClock++; /* time rolls on */ +#endif /* !defined(PURE3274) */ + if (Wcc & WCC_RESTORE) { +#if !defined(PURE3274) + if (TransparentClock != OutputClock) { + AidByte = 0; + } +#else /* !defined(PURE3274) */ + AidByte = 0; +#endif /* !defined(PURE3274) */ + UnLocked = 1; + ResetOiaSystemLocked(&OperatorInformationArea); + SetOiaModified(); + SetPsModified(); + TerminalIn(); + } + if (Wcc & WCC_ALARM) { + RingBell((char *)0); + } + } + LastWasTerminated = control; /* state for next time */ + return(origCount); + } else { + return(origCount-count); + } +} + +/* + * Init3270() + * + * Initialize any 3270 (controller) variables to an initial state + * in preparation for accepting a connection. + */ + +void +Init3270() +{ + int i; + + OptInit(); /* initialize mappings */ + + ClearArray(Host); + + ClearArray(Orders); + for (i = 0; i <= highestof(orders_def); i++) { + Orders[orders_def[i].code] = 1; + } + + DeleteAllFields(); /* Clear screen */ + Lowest = HighestScreen()+1; + Highest = LowestScreen()-1; + CursorAddress = BufferAddress = SetBufferAddress(0,0); + UnLocked = 1; +#if !defined(PURE3274) + OutputClock = 1; + TransparentClock = -1; +#endif /* !defined(PURE3274) */ + SetOiaReady3274(&OperatorInformationArea); +} + + +void +Stop3270() +{ + ResetOiaReady3274(&OperatorInformationArea); +} diff --git a/usr.bin/tn3270/ctlr/screen.h b/usr.bin/tn3270/ctlr/screen.h new file mode 100644 index 0000000..9dd8595 --- /dev/null +++ b/usr.bin/tn3270/ctlr/screen.h @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)screen.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_SCREEN + +/* defines and defines to describe how to deal with the screen */ + +#if !defined(MSDOS) +#define MAXNUMBERLINES 43 /* 3278-4 */ +#define MAXNUMBERCOLUMNS 132 /* 3278-5 */ +#define MAXSCREENSIZE 3564 /* (27*132) 3278-5 */ +#else /* !defined(MSDOS) */ /* MSDOS has memory constraints */ +#define MAXNUMBERLINES 25 /* XXX */ +#define MAXNUMBERCOLUMNS 80 +#define MAXSCREENSIZE (MAXNUMBERLINES*MAXNUMBERCOLUMNS) +#endif /* !defined(MSDOS) */ /* MSDOS has memory constraints */ +#define LowestScreen() 0 +#define HighestScreen() (ScreenSize-1) + +#define ScreenLineOffset(x) ((x)%NumberColumns) +#define ScreenLine(x) ((int)((x)/NumberColumns)) +#define ScreenInc(x) (((x)==HighestScreen())? LowestScreen():x+1) +#define ScreenDec(x) (((x)==LowestScreen())? HighestScreen():x-1) +#define ScreenUp(x) (((x)+(ScreenSize-NumberColumns))%ScreenSize) +#define ScreenDown(x) (((x)+NumberColumns)%ScreenSize) +#define IsOrder(x) (Orders[x]) +#define BAIC(x) ((x)&0x3f) +#define CIAB(x) (CIABuffer[(x)&0x3f]) +#define BufferTo3270_0(x) (CIABuffer[(int)((x)/0x40)]) +#define BufferTo3270_1(x) (CIABuffer[(x)&0x3f]) +#define Addr3270(x,y) (BAIC(x)*64+BAIC(y)) +#define SetBufferAddress(x,y) ((x)*NumberColumns+(y)) + +/* These know how fields are implemented... */ + +#define WhereAttrByte(p) (IsStartField(p)? p: FieldDec(p)) +#define WhereHighByte(p) ScreenDec(FieldInc(p)) +#define WhereLowByte(p) ScreenInc(WhereAttrByte(p)) +#define FieldAttributes(x) (IsStartField(x)? GetHost(x) : \ + GetHost(WhereAttrByte(x))) +#define FieldAttributesPointer(p) (IsStartFieldPointer(p)? \ + GetHostPointer(p): \ + GetHost(WhereAttrByte((p)-&Host[0]))) + +/* + * The MDT functions need to protect against the case where the screen + * is unformatted (sigh). + */ + +/* Turn off the Modified Data Tag */ +#define TurnOffMdt(x) \ + if (HasMdt(WhereAttrByte(x))) { \ + ModifyMdt(x, 0); \ + } + +/* Turn on the Modified Data Tag */ +#define TurnOnMdt(x) \ + if (!HasMdt(WhereAttrByte(x))) { \ + ModifyMdt(x, 1); \ + } + +/* If this location has the MDT bit turned on (implies start of field) ... */ +#define HasMdt(x) \ + ((GetHost(x)&(ATTR_MDT|ATTR_MASK)) == (ATTR_MDT|ATTR_MASK)) + + /* + * Is the screen formatted? Some algorithms change depending + * on whether there are any attribute bytes lying around. + */ +#define FormattedScreen() \ + ((WhereAttrByte(0) != 0) || ((GetHost(0)&ATTR_MASK) == ATTR_MASK)) + + /* field starts here */ +#define IsStartField(x) ((GetHost(x)&ATTR_MASK) == ATTR_MASK) +#define IsStartFieldPointer(p) ((GetHostPointer(p)&ATTR_MASK) == ATTR_MASK) + +#define NewField(p,a) SetHost(p, (a)|ATTR_MASK) +#define DeleteField(p) SetHost(p, 0) +#define DeleteAllFields() + +/* The following are independent of the implementation of fields */ +#define IsProtectedAttr(p,a) (IsStartField(p) || ((a)&ATTR_PROT)) +#define IsProtected(p) IsProtectedAttr(p,FieldAttributes(p)) + +#define IsUnProtected(x) (!IsProtected(x)) + +#define IsAutoSkip(x) (FieldAttributes(x)&ATTR_AUTO_SKIP) + +#define IsNonDisplayAttr(c) (((c)&ATTR_DSPD_MASK) == ATTR_DSPD_NONDISPLAY) +#define IsNonDisplay(p) IsNonDisplayAttr(FieldAttributes(p)) + +#define IsHighlightedAttr(c) \ + (((c)&ATTR_DSPD_MASK) == ATTR_DSPD_HIGH) +#define IsHighlighted(p) \ + (IsHighlightedAttr(FieldAttributes(p)) && !IsStartField(p)) + +typedef unsigned char ScreenImage; + +extern int + FieldFind(); + +extern char + CIABuffer[]; + +#define GetGeneric(i,h) (h)[i] +#define GetGenericPointer(p) (*(p)) +#define SetGeneric(i,c,h) ((h)[i] = (c)) +#define ModifyGeneric(i,what,h) {(h)[i] what;} + +#define GetHost(i) GetGeneric(i,Host) +#define GetHostPointer(p) GetGenericPointer(p) +#define SetHost(i,c) SetGeneric(i,c,Host) +#define ModifyHost(i,what) ModifyGeneric(i,what,Host) diff --git a/usr.bin/tn3270/ctlr/scrnctlr.h b/usr.bin/tn3270/ctlr/scrnctlr.h new file mode 100644 index 0000000..8c140c6 --- /dev/null +++ b/usr.bin/tn3270/ctlr/scrnctlr.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)scrnctlr.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * definitions that have to do with the interface between the + * controller and the screen. + */ + +#define DISP_AMPERSAND 0x30 +#define DISP_BLANK 0x10 +#define DISP_CENTSIGN 0x1b +#define DISP_DUP 0x9f +#define DISP_FM 0x9e +#define DISP_GREATER_THAN 0x08 +#define DISP_NULL 0x00 +#define DISP_QUESTION 0x18 diff --git a/usr.bin/tn3270/ctlr/unix.kbd b/usr.bin/tn3270/ctlr/unix.kbd new file mode 100644 index 0000000..ad41eec --- /dev/null +++ b/usr.bin/tn3270/ctlr/unix.kbd @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)unix.kbd 8.1 (Berkeley) 6/6/93 + */ + +/* + * keynumber [ scancode [ unshifted [ shifted [ alted [ shiftalted ] ] ] ] ] + * + * keynumber is in decimal, and starts in column 1. + * scancode is hexadecimal. + * unshifted, etc. - these are either a single ascii character, + * or the name of a function or an AID-generating key. + * + * all fields are separated by a single space. + */ + +extern struct hits hits[]; +1 0e ` ~ LPRT +2 16 1 ! XON +3 1e 2 @ XOFF +4 26 3 # ALTK +5 25 4 $ ESCAPE +6 2e 5 % DISC +7 36 6 ^ MASTER_RESET +8 3d 7 & RESHOW +9 3e 8 * FLINP +10 46 9 ( SYNCH +11 45 0 ) INIT +12 4e - _ PCOFF +13 55 = + PCON +14 5d APLON APLOFF APLEND +15 66 LEFT +16 0d TAB BTAB +17 15 q Q FIELDEND +18 1d w W WORDEND +19 24 e E WORDBACKTAB +20 2d r R FERASE +21 2c t T WERASE +22 35 y Y ERASE +23 3c u U CLRTAB +24 43 i I SETHOM +25 44 o O SETMRG +26 4d p P UNDENT +27 54 [ { INDENT +28 5b \ | SETTAB +29 5c DELTAB COLTAB COLBAK +30 14 CAPS_LOCK +31 1c a A WORDTAB +32 1b s S CURSEL +33 23 d D VERTICAL_BAR +34 2b f F CENTSIGN +35 34 g G PF25 +36 33 h H PF26 +37 3b j J PF27 +38 42 k K PF28 +39 4b l L PF29 +40 4c ; : PF30 +41 52 ' " PF31 +42 53 ] } PF32 +43 5a NL +44 12 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +45 13 < > PF33 +46 1a z Z PF34 +47 22 x X PF35 +48 21 c C PF36 +49 2a v V +50 32 b B +51 31 n N +52 3a m M +53 41 , < +54 49 . > +55 4a / ? +56 51 +57 59 MAKE_SHIFT MAKE_SHIFT MAKE_SHIFT +58 11 RESET NULL DVCNL +59 +60 19 MAKE_ALT MAKE_ALT MAKE_ALT +61 29 SPACE SPACE +62 39 MAKE_ALT MAKE_ALT MAKE_ALT +63 +64 58 ENTER +65 06 CLEAR NULL TEST +66 0c NULL NULL ATTN +67 0b EEOF NULL EINP +68 0a +69 09 MAKE_CTRL +70 05 ATTN NULL TREQ +71 04 +72 03 +73 83 +74 01 +75 67 PA1 DP +76 64 BTAB +77 +78 61 LEFT NULL LEFT2 +79 +80 6e PA2 FM +81 65 INSRT +82 63 UP +83 62 NULL NULL HOME +84 60 DOWN +85 6f PA3 +86 6d DELETE +87 +88 6a RIGHT NULL RIGHT2 +89 +90 76 +91 6c 7 +92 6b 4 +93 69 1 +94 68 +95 77 +96 75 8 +97 73 5 +98 72 2 +99 70 0 +100 7e , +101 7d 9 +102 74 6 +103 7a 3 +104 71 . +105 84 SPACE +106 7c TAB +107 7b - +108 79 ENTER +109 78 +110 07 PF1 +111 0f PF2 +112 17 PF3 +113 1f PF4 +114 27 PF5 +115 2f PF6 +116 37 PF7 +117 3f PF8 NULL MONOCASE +118 47 PF9 +119 4f PF10 +120 56 PF11 +121 5e PF12 +122 08 PF13 +123 10 PF14 +124 18 PF15 +125 20 PF16 +126 28 PF17 +127 30 PF18 +128 38 PF19 +129 40 PF20 +130 48 PF21 +131 50 PF22 +132 57 PF23 +133 5f PF24 +134 92 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +135 D9 BREAK_SHIFT BREAK_SHIFT BREAK_SHIFT +136 99 BREAK_ALT BREAK_ALT BREAK_ALT +137 B9 BREAK_ALT BREAK_ALT BREAK_ALT diff --git a/usr.bin/tn3270/distribution/README b/usr.bin/tn3270/distribution/README new file mode 100644 index 0000000..29afc73 --- /dev/null +++ b/usr.bin/tn3270/distribution/README @@ -0,0 +1,99 @@ +Welcome to the new tn3270 - version 4.1.1. + +This version consists entirely of bug fixes to the August 1987 beta release +of tn3270. This version will now deal with CICS and VM/XA on the IBM +side, and with SunOS 4.0 on Sun 3's and Sun 4's. + +This version has been tested on various versions of BSD Unix, including +4.2 and 4.3 (but there are never vanilla versions) and the post-4.3 systems +running at Berkeley. It has been tested on CCI's, Vaxen, Sun 3's and Sun 4's. +However, it doesn't necessarily work on all systems (nor has the testing +been as intensive as one might like). + +This version should build on any Berkeley-derived system. + +There are two alternate make files: ./makefile_4.2 and telnet/Makefile_ultrix. + +**** Try ./makefile_4.2 if you get compile-time errors, or get + "multiply defined" messages for "_putchar" from the loader. + +**** Try telnet/Makefile_ultrix if your make(1) utility doesn't + support VPATH. Also try this makefile if your ld(1) doesn't + support the -r flag correctly. + +The bad news is that I've had to drop MS-DOS support. The good news here is +that there are various versions available for MS-DOS (from FTP Software in +Cambridge, Mass.; from IBM; from Excelan; and probably from others). The +hooks are still there, as well as some code to update the screen. However, +I just haven't had the time to produce a fully integrated version that would +"just make". I suspect that a future release may have MS-DOS support back +in it. + +There is no Mac support. Contact Peter DiCamillo at Brown University if +you need a Mac tn3270. + +The main code change in this version is to what used to be called "telnet.c". +This is now replaced with a version of telnet (substantially what appeared +in the "4.3tahoe" release from CSRG) which is broken into separate files. + +Here is an overview of the directory structure: + + api/ General library of function needed by API + (and, to some extent, by the rest of tn3270). + + arpa/ Location of "telnet.h" (for non-4.3 systems). + + ascii/ Routines necessary to handle the case of running + from an ASCII-oriented system (ie: unix). + + ctlr/ The main part of the emulator. Handles 3270 scan + codes, 3270 data stream, 3270 display codes, + and EBCDIC. Also, the internal API function + lives here. + + general/ Some general subroutines and data structures of + interest to the emulator only. + + sys_curses/ System-dependent code for a curses-based environment. + + sys_dos/ System-dependent code for an MS-DOS-base environment. + Remember that this is included for your developmental + needs (ie: it doesn't work). + + telnet/ Where the telnet portion of tn3720 is built. + + tools/ Various tools. Most of these are used during the + build process. One (prt3270) is a debugging tool. + One (mkmake.y) is quite horrible, and attempts to + transform Unix makefiles into PC makefiles. + + utilities/ The source for tnrecv, which receives files + (fairly slowly) from an IBM host. We don't + include the IBM side, because we really aren't + happy with very much of it (except that it does, + sometimes, work). Hopefully, when we get past + the beta stage we will have more robust (and + complete) code to share. + +The fact that system dependancies are isolated should make it easy +to port to other systems. I would like to hear about problems porting +to new areas. + +In the August, 1987 README file, the following appeared: + +> WHAT IS NOT IN THIS VERSION (sigh): + +> 1) We don't have a native X version yet. I am waiting for X version 11 +> (though this is mostly an excuse; I could have done version 10, +> but I haven't had the time). + +> 2) We don't process structured fields. + +> 3) We don't do 3270-style graphics (ala 3193, say). + +> The above three items WILL be in the next version, which should come +> along "any day now" (say 6 months) (but, they WON'T be in the production +> release of this version). + +The next piece of bad news is that none of the above have happened yet, +and I don't know when they might occur. diff --git a/usr.bin/tn3270/distribution/arpa/makefile b/usr.bin/tn3270/distribution/arpa/makefile new file mode 100644 index 0000000..2cf3bc0 --- /dev/null +++ b/usr.bin/tn3270/distribution/arpa/makefile @@ -0,0 +1,67 @@ +# @(#)makefile 8.1 (Berkeley) 6/6/93 + +# msdos versus unix defines +O = .o +#PC_O = .obj + +X = +#PC_X = .exe + +L = +#PC_L = -link + +CC = cc +#PC_CC = cl + +MV = mv +#PC_MV = rename + +RM = rm -f +#PC_RM= erase + +LINT_ARGS = +#PC_LINT_ARGS = -DLINT_ARGS + +DEBUG_FLAGS = -g +#PC_DEBUG_FLAGS = -Zi -Od + +AR = ar +AR1 = cr +AR2 = +AR3 = +#PC_AR = lib +#PC_AR1 = +#PC_AR2 = + +#PC_AR3 = ";" + +RANLIB = ranlib +#PC_RANLIB = echo "Done with " + +PRINT = lpr -p + +ALLC = +ALLH = telnet.h + +ALLPRINT = ${ALLH} ${ALLC} + +ALLSOURCE = ${ALLPRINT} makefile makefile.mak + +clean: + +sccsclean: + -sccs clean + -sccs get makefile + +action: + ${ACTION} + +print: + ${PRINT} ${ALLPRINT} + + +sourcelist: ${ALLSOURCE} + @for i in ${ALLSOURCE}; \ + do (echo ${DIRPATH}$$i); done + +.DEFAULT: + sccs get $< diff --git a/usr.bin/tn3270/distribution/arpa/telnet.h b/usr.bin/tn3270/distribution/arpa/telnet.h new file mode 100644 index 0000000..eeb72c2 --- /dev/null +++ b/usr.bin/tn3270/distribution/arpa/telnet.h @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 1983, 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. + * + * @(#)telnet.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", +}; +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((x) <= TELCMD_LAST && (x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] +#endif + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + +#define NTELOPTS (1+TELOPT_LINEMODE) +#ifdef TELOPTS +char *telopts[NTELOPTS] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_LINEMODE +#define TELOPT_OK(x) ((x) <= TELOPT_LAST && (x) >= TELOPT_FIRST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 + +#define MODE_MASK (MODE_EDIT|MODE_TRAPSIG|MODE_ACK) + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x40 +#define MODE_ECHO 0x80 +#define MODE_FORCE 0x20 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +#define SLC_NAMES "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2" + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 diff --git a/usr.bin/tn3270/distribution/makefile_4.2 b/usr.bin/tn3270/distribution/makefile_4.2 new file mode 100644 index 0000000..b8e5eb8e --- /dev/null +++ b/usr.bin/tn3270/distribution/makefile_4.2 @@ -0,0 +1,268 @@ +# @(#)makefile 3.5 (Berkeley) 5/15/88 + +# This makefile will make tn3270 on Vax 4.2 systems. Notice, however, +# that on an ultrix system you will need to use the Makefile_ultrix in +# telnet/ rather than the Makefile already in that directory. + +# Makefile for tn3270 and friends... +# +# This is the makefile for tn3270. Note that we use the 4.3+ telnet +# (compiled with special options; see below) to provide the telnet +# support we need. +# +# The following are the defines that may be passed (via the cc +# -D option) to the compiler. +# +# TN3270 - This is to be linked with tn3270. Necessary +# for creating tn3270. Only for compiling +# telnet. +# +# NOT43 - Allows the program to compile and run on +# a 4.2BSD system. +# +# PUTCHAR - Within tn3270, on a NOT43 system, +# allows the use of the 4.3 curses +# (greater speed updating the screen). +# You need the 4.3 curses for this to work. +# +# FD_SETSIZE - On whichever system, if this isn't defined, +# we patch over the FD_SET, etc., macros with +# some homebrewed ones. +# +# SO_OOBINLINE - This is a socket option which we would like +# to set to allow TCP urgent data to come +# to us "inline". This is NECESSARY for +# CORRECT operation, and desireable for +# simpler operation. +# +# LNOFLSH - Detects the presence of the LNOFLSH bit +# in the tty structure. +# +# +# Here are some which are used throughout the system: +# +# unix - Compiles in unix specific stuff. +# +# msdos - Compiles in msdos specific stuff. +# + +# msdos versus unix defines +O = .o +#PC_O = .obj + +X = +#PC_X = .exe + +L = +#PC_L = -link + +CC = cc +#PC_CC = cl + +MV = mv +#PC_MV = rename + +RM = rm -f +#PC_RM= erase + +LINT_ARGS = +#PC_LINT_ARGS = -DLINT_ARGS + +DEBUG_FLAGS = -g +#PC_DEBUG_FLAGS = -Zi -Od + +AR = ar +AR1 = cr +AR2 = +AR3 = +#PC_AR = lib +#PC_AR1 = +#PC_AR2 = + +#PC_AR3 = ";" + +RANLIB = ranlib +#PC_RANLIB = echo "Done with " + + +PRINT = print +ACTION = @sccs tell + +DEFINES = -DNOT43 ${LINT_ARGS} + +INCLUDES = -I. -I.. + +OPTIMIZE = -O +OPTIMIZE = ${DEBUG_FLAGS} + +CFLAGS = $(OPTIMIZE) $(INCLUDES) $(DEFINES) + +# Lint flags +LINTFLAGS = -hbxaz +# How to install the bloody thing... + +DESTDIR= + +BINDIR = $(DESTDIR)/usr/ucb + +# Names for the terminal libraries... +LIBCURSES = -lcurses +LIBTERM = -ltermlib + +#PC_LIBCURSES = +#PC_LIBTERM = + +# The source files... +ALLH = telnet.ext + +MSMAIN = ascii/mset.c + +ALLC = + +ALLO = mset$O + +ALLHC= ${ALLH} ${ALLC} +ALLPRINT = ${ALLHC} + +ALLSOURCE = ${ALLPRINT} makefile makefile.mak makefile_4.2 README + +SYS = sys_curses +#PC_SYS = sys_dos + +# The places where the various components live... + +SUBDIR = api ascii ctlr general ${SYS} telnet + +# The following are directories we don't do regular make's in, but +# we do make everywhere, print, and sourcelist in. + +EXTRADIR = arpa sys_dos tools utilities + +# The libraries we use. The order here is important. +# syslib.a and ctlrlib.a should come first, then the rest. +SUBLIB = ${SYS}/syslib.a ctlr/ctlrlib.a \ + ascii/asciilib.a general/generallib.a + +.s.o: + /lib/cpp -E $< | as -o $@ + +.c.obj: + ${CC} ${CFLAGS} -c $< + +all: FRC tn3270$X mset$X + +FRC: + for i in ${SUBDIR}; \ + do (cd $$i; make ${MFLAGS} "CFLAGS=${CFLAGS}"); done + +tn3270$X: telnet/telprog.o ${SUBLIB} api/apilib.a + ${CC} ${CFLAGS} -o tn3270 telnet/telprog.o \ + $L ${SUBLIB} api/apilib.a $(LIBCURSES) $(LIBTERM) + +#PC_tn3270$X: +#PC_ link <@< +#PC_ telnet +#PC_ tn3270 +#PC_ nul +#PC_ ${SUBLIB} api/apilib.a+ +#PC_ \lib\ublib\ubtcp +#PC_ _PC_< + +mset$X: mset$O ascii/map3270$O + ${CC} ${CFLAGS} -o mset mset$O ascii/map3270$O $L api/apilib.a + +mset$O: $(MSMAIN) + $(CC) $(CFLAGS) -c $(MSMAIN) + +install: tn3270$X mset$X + install -m 755 -o bin -g bin -s tn3270 $(BINDIR) + install -m 755 -o bin -g bin -s mset $(BINDIR) + +action: + ${ACTION} + +clist: ${ALLHC} + @for i in ${SUBDIR}; \ + do (cd $$i; make ${MFLAGS} "DIRPATH=${DIRPATH}$$i/" \ + clist); done + +hclist: ${ALLHC} + @for i in ${SUBDIR}; \ + do (cd $$i; make ${MFLAGS} "DIRPATH=${DIRPATH}$$i/" \ + hclist); done + +everywhere: action + for i in ${SUBDIR} ${EXTRADIR}; \ + do (echo "[$$i]"; cd $$i; make ${MFLAGS} action \ + "ACTION=${ACTION}"); done + +clean: + for i in $(ALLO) mset tn3270 errs makefile.bak; \ + do (${RM} $$i); done + for i in ${SUBDIR} ${EXTRADIR}; \ + do (cd $$i; make ${MFLAGS} clean); done + +sccsclean: + -sccs clean + -sccs get makefile + for i in ${SUBDIR} ${EXTRADIR}; \ + do (cd $$i; make ${MFLAGS} sccsclean); done + +print: + ${PRINT} ${ALLPRINT} + for i in ${SUBDIR} ${EXTRADIR}; \ + do (cd $$i; make ${MFLAGS} "PRINT=${PRINT}" print); done + +tags: ${ALLC} ${ALLH} + ctags -t `make ${MFLAGS} hclist` + +sourcelist: ${ALLSOURCE} + @for i in ${ALLSOURCE}; \ + do (echo ${DIRPATH}$$i); done + @for i in ${SUBDIR} ${EXTRADIR}; \ + do (cd $$i; make ${MFLAGS} "DIRPATH=${DIRPATH}$$i/" \ + sourcelist); done + +lint: + lint ${LINTFLAGS} ${INCLUDES} ${DEFINES} -DTN3270 \ + `make clist` -lcurses + +lintmset: + lint ${LINTFLAGS} ${INCLUDES} ${DEFINES} ${MSMAIN} \ + ascii/map3270.c -lcurses + +makefiles.pc: tools/mkmake + for i in . ${SUBDIR} ${EXTRADIR}; \ + do (sed -e "s/lib\.a/.lib/g" -e "s/^#PC_//" < $$i/makefile | \ + ./tools/mkmake | \ + sed -e "sx/x\\\\xg" -e "s/[ ]*_PC_//" > $$i/makefile.mak); \ + done + +tools/mkmake: + (cd tools; make mkmake) + +.DEFAULT: + sccs get $< + +depend: thisdepend + for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} depend); done + +thisdepend: + echo > eddep.c + grep '^#include' ${ALLC} eddep.c | grep -v '<' | \ + sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ + -e 's/\.c/$$O/' | \ + awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ + else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ + else rec = rec " " $$2 } } \ + END { print rec } ' > makedep + echo '$$r makedep' >>eddep + echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + -rm -f makefile.bak + cp makefile makefile.bak + ed - makefile < eddep + rm eddep makedep eddep.c + +# DO NOT DELETE THIS LINE + diff --git a/usr.bin/tn3270/distribution/sys_dos/makefile b/usr.bin/tn3270/distribution/sys_dos/makefile new file mode 100644 index 0000000..4188f9f --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/makefile @@ -0,0 +1,127 @@ +# @(#)makefile 8.1 (Berkeley) 6/6/93 + +# msdos versus unix defines +O = .o +#PC_O = .obj + +X = +#PC_X = .exe + +L = +#PC_L = -link + +CC = cc +#PC_CC = cl + +MV = mv +#PC_MV = rename + +RM = rm -f +#PC_RM= erase + +LINT_ARGS = +#PC_LINT_ARGS = -DLINT_ARGS + +DEBUG_FLAGS = -g +#PC_DEBUG_FLAGS = -Zi -Od + +AR = ar +AR1 = cr +AR2 = +AR3 = +#PC_AR = lib +#PC_AR1 = +#PC_AR2 = + +#PC_AR3 = ";" + +RANLIB = ranlib +#PC_RANLIB = echo "Done with " + +PRINT = print + +DEFINES = ${LINT_ARGS} + +INCLUDES = -I. + +OPTIMIZE = -O +OPTIMIZE = ${DEBUG_FLAGS} + +CFLAGS = $(OPTIMIZE) $(INCLUDES) $(DEFINES) + +# Lint flags +LINTFLAGS = -hbxaz + +ALLH = spint.h video.h + +ALLC = spintc.c system.c termout.c + +ALLASM = spintasm.asm support.asm + +ALLO = spintasm$O spintc$O support$O system$O termout$O + +ALLPRINT = ${ALLH} ${ALLASM} ${ALLC} + +ALLSOURCE = ${ALLPRINT} makefile makefile.mak + +.c.obj: + ${CC} ${CFLAGS} -c $< + +syslib.a: $(ALLO) + ${RM} $@ + for i in ${ALLO}; do (${AR} ${AR1} $@ ${AR2} $$i${AR3}); done + ${RANLIB} $@ + +clean: + for i in $(ALLO) errs makefile.bak syslib.a; \ + do (${RM} $$i); done + +sccsclean: + -sccs clean + -sccs get makefile + +sourcelist: ${ALLSOURCE} + @for i in ${ALLSOURCE}; \ + do (echo ${DIRPATH}$$i); done + +print: + ${PRINT} ${ALLPRINT} + +tags: ${ALLC} ${ALLH} + ctags -t ${ALLC} ${ALLH} + +action: + ${ACTION} + +lint: + lint ${LINTFLAGS} ${INCLUDES} ${DEFINES} -DTN3270 \ + ${TNMAIN} ${MOSTC} -lcurses + lint ${LINTFLAGS} ${INCLUDES} ${DEFINES} ${MSMAIN} map3270.c -lcurses + +.DEFAULT: + sccs get $< + +depend: + grep '^#include' ${ALLC} ${ALLH} | grep -v '<' | \ + sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ + -e 's/\.c/$$O/' | \ + awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ + else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ + else rec = rec " " $$2 } } \ + END { print rec } ' > makedep + echo '$$r makedep' >>eddep + echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + -rm -f makefile.bak + cp makefile makefile.bak + ed - makefile < eddep + rm eddep makedep + +# DO NOT DELETE THIS LINE + +spintc$O: ../general/general.h spint.h +system$O: ../general/general.h ../ctlr/api.h spint.h ../general/globals.h +termout$O: ../general/general.h ../api/disp_asc.h +termout$O: ../ctlr/hostctlr.h +termout$O: ../ctlr/oia.h +termout$O: ../ctlr/screen.h ../general/globals.h video.h diff --git a/usr.bin/tn3270/distribution/sys_dos/spint.h b/usr.bin/tn3270/distribution/sys_dos/spint.h new file mode 100644 index 0000000..023ee52 --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/spint.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)spint.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * The 'spint' (spawn and interrupt) routines use this structure. + * + * Note that spint_asm.asm contains an Assembly language version of + * the following, so keep changes in synch! + */ + +typedef struct { + union REGS regs; + struct SREGS sregs; + int int_no; /* Which interrupt to wait on */ + int done; /* Are we done, or just took an interrupt? */ + int rc; /* return code */ +} Spint; diff --git a/usr.bin/tn3270/distribution/sys_dos/spintasm.asm b/usr.bin/tn3270/distribution/sys_dos/spintasm.asm new file mode 100644 index 0000000..72efdec --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/spintasm.asm @@ -0,0 +1,252 @@ +; Copyright (c) 1988, 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. +; +; @(#)spintasm.asm 8.1 (Berkeley) 6/6/93 +; + +; The code in this file complete the spint calls + +spint struc +; union REGS +spint_ax dw 1 +spint_bx dw 1 +spint_cx dw 1 +spint_dx dw 1 +spint_si dw 1 +spint_di dw 1 +spint_cflag dw 1 +; struct SREGS +spint_es dw 1 +spint_cs dw 1 +spint_ss dw 1 +spint_ds dw 1 +; int intno +spint_intno dw 1 +; int done +spint_done dw 1 +; int rc +spint_rc dw 1 +; +spint ends + + +ENTER MACRO + ; Begin enter + push bp + mov bp,sp + + push ax + push bx + push cx + push dx + push bp + push di + push si + push ds + push es + pushf + + mov cs:start_sp, sp + mov cs:start_ss, ss + ; End enter + ENDM + +LEAVE MACRO + ; Begin leave + cli + mov sp, cs:start_sp + mov ss, cs:start_ss + sti + + popf + pop es + pop ds + pop si + pop di + pop bp + pop dx + pop cx + pop bx + pop ax + + mov sp,bp + pop bp + ret + ; End leave + ENDM + +GETREGS MACRO wherefrom + mov si, wherefrom + mov spint_segment, ds + mov spint_offset, si + + mov ax, spint_ax[si] + mov bx, spint_bx[si] + mov cx, spint_cx[si] + mov dx, spint_dx[si] + ; XXX mov si, spint_si[si] + mov di, spint_di[si] + mov es, spint_es[si] + ; Now, need to do DS, SI + push spint_ds[si] + mov si, spint_si[si] + pop ds + ENDM + + +SETREGS MACRO + mov cs:old_si, si + mov cs:old_ds, ds + + mov ds, cs:spint_segment + mov si, cs:spint_offset + + mov spint_ax[si], ax + mov spint_bx[si], bx + mov spint_cx[si], cx + mov spint_dx[si], dx + + mov spint_si[si], si + mov spint_di[si], di + + mov spint_cs[si], cs + mov spint_ds[si], ds + mov spint_es[si], es + mov spint_ss[si], ss + ; now, need to do SI, DS + mov ax, old_si + mov spint_si[si], ax + mov ax, old_ds + mov spint_ds[si], ax + ENDM + + +_TEXT segment byte public 'CODE' +_TEXT ends + +_DATA segment word public 'DATA' +_DATA ends + +CONST segment word public 'CONST' +CONST ends + +_BSS segment word public 'BSS' +_BSS ends + +DGROUP group CONST, _BSS, _DATA + + assume cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP + +_TEXT segment + +start_sp dw 1 dup (?) ; For use in our 'longjmp' +start_ss dw 1 dup (?) ; For use in our 'longjmp' + +spint_segment dw 1 dup (?) ; Segment of spawn control block +spint_offset dw 1 dup (?) ; Offset of spawn control block + +old_si dw 1 dup (?) ; SI of interrupt issuer (temporary) +old_ds dw 1 dup (?) ; DS of interrupt issuer (temporary) + +issuer_ss dw 1 dup (?) ; ss of person who called us (permanent) +issuer_sp dw 1 dup (?) ; sp of person who called us (permanent) + +int21_stack db 100 dup (?) ; Stack for int21. + +; +; _spint_int gets control on an interrupt. It switches the stack +; and does a 'return' from _spint_start. +; + public __spint_int + +__spint_int proc near + mov cs:issuer_sp, sp + mov cs:issuer_ss, ss + sti + + SETREGS + + LEAVE +__spint_int endp + +; +; _spint_start issues the dos interrupt after setting up the passed +; registers. When control returns to it, it sets spint->done to non-zero. +; + public __spint_start + +__spint_start proc near + ENTER + + GETREGS 4[bp] + + ; Now, switch to a different (short) stack. This is so + ; that our games won't mess up the stack int 21 (hardware and, + ; possibly, software) stores things on. + + cli + mov cs:int21_stack, cs + mov ss, cs:int21_stack + mov sp, offset int21_stack + add sp, (length int21_stack) - 4 + sti + + int 21H ; Issue DOS interrupt + + SETREGS + + mov ds, cs:spint_segment + mov si, cs:spint_offset + mov spint_done[si], 1 ; We are done + + LEAVE +__spint_start endp + +; +; After _spint_int has faked a return from start_spawn, we come here to +; return to the interrupt issuer. +; + public __spint_continue + +__spint_continue proc near + ENTER + + GETREGS 4[bp] + + mov sp, cs:issuer_sp ; Restore SP + mov ss, cs:issuer_ss ; Restore SS + + iret +__spint_continue endp + +_TEXT ends + + end diff --git a/usr.bin/tn3270/distribution/sys_dos/spintc.c b/usr.bin/tn3270/distribution/sys_dos/spintc.c new file mode 100644 index 0000000..aa16405 --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/spintc.c @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)spintc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include "../general/general.h" +#include "spint.h" + +#define PSP_ENVIRONMENT 0x2c +#define PSP_FCB1 0x5c +#define PSP_FCB2 0x6c + +typedef struct { + int + environment, /* Segment address of environment */ + cmd_ptr_offset, /* Offset of command to execute */ + cmd_ptr_segment, /* Segment where command lives */ + fcb1_ptr_offset, /* Offset of FCB 1 */ + fcb1_ptr_segment, /* Segment of FCB 1 */ + fcb2_ptr_offset, /* Offset of FCB 2 */ + fcb2_ptr_segment; /* Segment of FCB 2 */ +} ExecList; + + +static int int_offset, int_segment; + + +void +spint_finish(spint) +Spint *spint; +{ + union REGS regs; + struct SREGS sregs; + + if (spint->done == 0) { + return; /* Not done yet */ + } + + /* + * Restore old interrupt handler. + */ + + regs.h.ah = 0x25; + regs.h.al = spint->int_no; + regs.x.dx = int_offset; + sregs.ds = int_segment; + intdosx(®s, ®s, &sregs); + + if (spint->regs.x.cflag) { + fprintf(stderr, "0x%x return code from EXEC.\n", spint->regs.x.ax); + spint->done = 1; + spint->rc = 99; + return; + } + + regs.h.ah = 0x4d; /* Get return code */ + + intdos(®s, ®s); + + spint->rc = regs.x.ax; +} + +void +spint_continue(spint) +Spint *spint; +{ + _spint_continue(spint); /* Return to caller */ + spint_finish(spint); +} + + +void +spint_start(command, spint) +char *command; +Spint *spint; +{ + ExecList mylist; + char *comspec; + void _spint_int(); + union REGS regs; + struct SREGS sregs; + + /* + * Get comspec. + */ + comspec = getenv("COMSPEC"); + if (comspec == 0) { /* Can't find where command.com is */ + fprintf(stderr, "Unable to find COMSPEC in the environment."); + spint->done = 1; + spint->rc = 99; /* XXX */ + return; + } + + /* + * Now, hook up our interrupt routine. + */ + + regs.h.ah = 0x35; + regs.h.al = spint->int_no; + intdosx(®s, ®s, &sregs); + + /* Save old routine */ + int_offset = regs.x.bx; + int_segment = sregs.es; + + regs.h.ah = 0x25; + regs.h.al = spint->int_no; + regs.x.dx = (int) _spint_int; + segread(&sregs); + sregs.ds = sregs.cs; + intdosx(®s, ®s, &sregs); + + /* + * Read in segment registers. + */ + + segread(&spint->sregs); + + /* + * Set up registers for the EXEC call. + */ + + spint->regs.h.ah = 0x4b; + spint->regs.h.al = 0; + spint->regs.x.dx = (int) comspec; + spint->sregs.es = spint->sregs.ds; /* Superfluous, probably */ + spint->regs.x.bx = (int) &mylist; + + /* + * Set up EXEC parameter list. + */ + + ClearElement(mylist); + mylist.cmd_ptr_offset = (int) command; + mylist.cmd_ptr_segment = spint->sregs.ds; + mylist.fcb1_ptr_offset = PSP_FCB1; + mylist.fcb1_ptr_segment = _psp; + mylist.fcb2_ptr_offset = PSP_FCB2; + mylist.fcb2_ptr_segment = _psp; + mylist.environment = *((int far *)(((long)_psp<<16)|PSP_ENVIRONMENT)); + + /* + * Call to assembly language routine to actually set up for + * the spint. + */ + + _spint_start(spint); + + spint_finish(spint); +} diff --git a/usr.bin/tn3270/distribution/sys_dos/support.asm b/usr.bin/tn3270/distribution/sys_dos/support.asm new file mode 100644 index 0000000..a51c41d --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/support.asm @@ -0,0 +1,60 @@ +; Copyright (c) 1988, 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. +; +; @(#)support.asm 8.1 (Berkeley) 6/6/93 +; + +_TEXT segment byte public 'CODE' +_TEXT ends + +_DATA segment word public 'DATA' +_DATA ends + +CONST segment word public 'CONST' +CONST ends + +_BSS segment word public 'BSS' +_BSS ends + +DGROUP group CONST, _BSS, _DATA + + assume cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP + +_TEXT segment + public _iret_subr + +_iret_subr proc far + iret +_iret_subr endp + +_TEXT ends + + end diff --git a/usr.bin/tn3270/distribution/sys_dos/system.c b/usr.bin/tn3270/distribution/sys_dos/system.c new file mode 100644 index 0000000..864926b --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/system.c @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)system.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include "../general/general.h" +#include "../ctlr/api.h" +#include "spint.h" + +#include "../general/globals.h" + + +static Spint spinted; +static char command[256]; +static int need_to_start = 0; + +/* + * shell_continue() actually runs the command, and looks for API + * requests coming back in. + * + * We are called from the main loop in telnet.c. + */ + +int +shell_continue() +{ + /* + * spint_start() returns when either the command has finished, or when + * the required interrupt comes in. In the latter case, the appropriate + * thing to do is to process the interrupt, and then return to + * the interrupt issuer by calling spint_continue(). + */ + if (need_to_start) { + need_to_start = 0; + spint_start(command, &spinted); + } + + if (spinted.done == 0) { + /* Process request */ + handle_api(&spinted.regs, &spinted.sregs); + spint_continue(&spinted); + } else { + char inputbuffer[100]; + + if (spinted.rc != 0) { + fprintf(stderr, "Process generated a return code of 0x%x.\n", + spinted.rc); + } + printf("[Hit return to continue]"); + fflush(stdout); + (void) gets(inputbuffer); + shell_active = 0; + setconnmode(); + ConnectScreen(); + } + return shell_active; +} + + +/* + * Called from telnet.c to fork a lower command.com. We + * use the spint... routines so that we can pick up + * interrupts generated by application programs. + */ + + +int +shell(argc,argv) +int argc; +char *argv[]; +{ + + ClearElement(spinted); + spinted.int_no = API_INTERRUPT_NUMBER; + if (argc == 1) { + command[0] = 0; + } else { + char *cmdptr; + int length; + + argc--; + argv++; + strcpy(command, " /c"); + cmdptr = command+strlen(command); + while (argc) { + if ((cmdptr+strlen(*argv)) >= (command+sizeof command)) { + fprintf(stderr, "Argument list too long at argument *%s*.\n", + *argv); + return 0; + } + *cmdptr++ = ' '; /* Blank separators */ + strcpy(cmdptr, *argv); + cmdptr += strlen(cmdptr); + argc--; + argv++; + } + length = strlen(command)-1; + if (length < 0) { + length = 0; + } + command[0] = length; + } + need_to_start = 1; + shell_active = 1; + return 1; /* Go back to main loop */ +} diff --git a/usr.bin/tn3270/distribution/sys_dos/termout.c b/usr.bin/tn3270/distribution/sys_dos/termout.c new file mode 100644 index 0000000..0339072 --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/termout.c @@ -0,0 +1,514 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)termout.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include "../general/general.h" + +#include "../telnet.ext" + +#include "../api/disp_asc.h" +#include "../ascii/map3270.ext" + +#include "../ctlr/hostctlr.h" +#include "../ctlr/externs.h" +#include "../ctlr/declare.h" +#include "../ctlr/oia.h" +#include "../ctlr/screen.h" + +#include "../general/globals.h" + +#include "video.h" + +extern void EmptyTerminal(); + +#define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ + terminalCursorAddress:UnLocked? CursorAddress: HighestScreen()) + + +static int terminalCursorAddress; /* where the cursor is on term */ +static int screenInitd; /* the screen has been initialized */ +static int screenStopped; /* the screen has been stopped */ + +static int needToRing; /* need to ring terinal bell */ + +typedef struct { + char + data, /* The data for this position */ + attr; /* The attributes for this position */ +} ScreenBuffer; + +ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS]; +ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]]; + +/* OurExitString - designed to keep us from going through infinite recursion */ + +static void +OurExitString(file, string, value) +FILE *file; +char *string; +int value; +{ + static int recursion = 0; + + if (!recursion) { + recursion = 1; + ExitString(file, string, value); + } +} + + +static void +GoAway(from, where) +char *from; /* routine that gave error */ +int where; /* cursor address */ +{ + char foo[100]; + + sprintf(foo, "ERR from %s at %d (%d, %d)\n", + from, where, ScreenLine(where), ScreenLineOffset(where)); + OurExitString(stderr, foo, 1); + /* NOTREACHED */ +} + +/* + * Routines to deal with the screen. These routines are lifted + * from mskermit. + */ + +#define CRT_STATUS 0x3da /* Color card */ +#define DISPLAY_ENABLE 0x08 /* Enable */ +#define scrseg() ((crt_mode == 7)? 0xb000 : 0xb800) +#define scrwait() if (crt_mode != 7) { \ + while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \ + ; \ + } \ + } +static int + crt_mode, + crt_cols, + crt_lins, + curpage; + +/* + * Set the cursor position to where it belongs. + */ + +static void +setcursor(row, column, page) +int + row, + column, + page; +{ + union REGS inregs, outregs; + + inregs.h.dh = row; + inregs.h.dl = column; + inregs.h.bh = page; + inregs.h.ah = SetCursorPosition; + + int86(BIOS_VIDEO, &inregs, &outregs); +} +/* + * Read the state of the video system. Put the cursor somewhere + * reasonable. + */ + +static void +scrini() +{ + union REGS inregs, outregs; + + inregs.h.ah = CurrentVideoState; + int86(BIOS_VIDEO, &inregs, &outregs); + + crt_mode = outregs.h.al; + crt_cols = outregs.h.ah; + crt_lins = 25; + curpage = outregs.h.bh; + + inregs.h.ah = ReadCursorPosition; + inregs.h.bh = curpage; + + int86(BIOS_VIDEO, &inregs, &outregs); + + if (outregs.h.dh > crt_lins) { + outregs.h.dh = crt_lins; + } + if (outregs.h.dl > crt_cols) { + outregs.h.dl = crt_cols; + } + inregs.h.dh = outregs.h.dh; + inregs.h.dl = outregs.h.dl; + inregs.h.bh = curpage; + + inregs.h.ah = SetCursorPosition; + int86(BIOS_VIDEO, &inregs, &outregs); +} + + +static void +scrwrite(source, length, offset) +ScreenBuffer *source; +int + length, + offset; +{ + struct SREGS segregs; + + segread(&segregs); /* read the current segment register */ + + scrwait(); + movedata(segregs.ds, source, scrseg(), sizeof *source*offset, + sizeof *source*length); +} + +static void +scrsave(buffer) +ScreenBuffer *buffer; +{ + struct SREGS segregs; + + segread(&segregs); /* read the current segment register */ + + scrwait(); + movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2); +} + +static void +scrrest(buffer) +ScreenBuffer *buffer; +{ + scrwrite(buffer, crt_cols*crt_lins, 0); +} + +static void +TryToSend() +{ +#define STANDOUT 0x0a /* Highlighted mode */ +#define NORMAL 0x02 /* Normal mode */ +#define NONDISPLAY 0x00 /* Don't display */ + +#define DoAttribute(a) \ + if (screenIsFormatted) { \ + if (IsNonDisplayAttr(a)) { \ + a = NONDISPLAY; /* don't display */ \ + } else if (IsHighlightedAttr(a)) { \ + a = STANDOUT; \ + } else { \ + a = NORMAL; \ + } \ + } else { \ + a = NORMAL; /* do display on unformatted */\ + } + ScreenImage *p, *upper; + ScreenBuffer *sp; + int fieldattr; /* spends most of its time == 0 or 1 */ + int screenIsFormatted = FormattedScreen(); + +/* OK. We want to do this a quickly as possible. So, we assume we + * only need to go from Lowest to Highest. However, if we find a + * field in the middle, we do the whole screen. + * + * In particular, we separate out the two cases from the beginning. + */ + if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { + sp = &Screen[Lowest]; + p = &Host[Lowest]; + upper = &Host[Highest]; + fieldattr = FieldAttributes(Lowest); + DoAttribute(fieldattr); /* Set standout, non-display status */ + + while (p <= upper) { + if (IsStartFieldPointer(p)) { /* New field? */ + Highest = HighestScreen(); + Lowest = LowestScreen(); + TryToSend(); /* Recurse */ + return; + } else if (fieldattr) { /* Should we display? */ + /* Display translated data */ + sp->data = disp_asc[GetHostPointer(p)]; + } else { + sp->data = ' '; + } + sp->attr = fieldattr; + p++; + sp++; + } + } else { /* Going from Lowest to Highest */ + ScreenImage *End = &Host[ScreenSize]-1; + + sp = Screen; + p = Host; + fieldattr = FieldAttributes(LowestScreen()); + DoAttribute(fieldattr); /* Set standout, non-display status */ + + while (p <= End) { + if (IsStartFieldPointer(p)) { /* New field? */ + fieldattr = FieldAttributesPointer(p); /* Get attributes */ + DoAttribute(fieldattr); /* Set standout, non-display */ + } + if (fieldattr) { /* Should we display? */ + /* Display translated data */ + sp->data = disp_asc[GetHostPointer(p)]; + } else { + sp->data = ' '; + } + sp->attr = fieldattr; + p++; + sp++; + } + } + terminalCursorAddress = CorrectTerminalCursor(); + /* + * We might be here just to update the cursor address. + */ + if (Highest >= Lowest) { + scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest); + } + setcursor(ScreenLine(terminalCursorAddress), + ScreenLineOffset(terminalCursorAddress), 0); + Lowest = HighestScreen()+1; + Highest = LowestScreen()-1; + if (needToRing) { + DataToTerminal("\7", 1); + needToRing = 0; + } + return; +} + +/* InitTerminal - called to initialize the screen, etc. */ + +void +InitTerminal() +{ + InitMapping(); /* Go do mapping file (MAP3270) first */ + if (!screenInitd) { /* not initialized */ + MaxNumberLines = 24; /* XXX */ + MaxNumberColumns = 80; /* XXX */ + scrini(); + scrsave(saveScreen); /* Save the screen buffer away */ + ClearArray(Screen); + terminalCursorAddress = SetBufferAddress(0,0); + screenInitd = 1; + screenStopped = 0; /* Not stopped */ + } +} + + +/* StopScreen - called when we are going away... */ + +void +StopScreen(doNewLine) +int doNewLine; +{ + if (screenInitd && !screenStopped) { + scrrest(saveScreen); + setcursor(NumberLines-1, 1, 0); + if (doNewLine) { + StringToTerminal("\r\n"); + } + EmptyTerminal(); + screenStopped = 1; + } +} + + +/* RefreshScreen - called to cause the screen to be refreshed */ + +void +RefreshScreen() +{ + Highest = HighestScreen(); + Lowest = LowestScreen(); + TryToSend(); +} + + +/* ConnectScreen - called to reconnect to the screen */ + +void +ConnectScreen() +{ + if (screenInitd) { + RefreshScreen(); + screenStopped = 0; + } +} + +/* LocalClearScreen() - clear the whole ball of wax, cheaply */ + +void +LocalClearScreen() +{ + Clear3270(); + Lowest = LowestScreen(); /* everything in sync... */ + Highest = HighestScreen(); + TryToSend(); +} + +/* + * Implement the bell/error message function. + */ + +int + bellwinup = 0; /* If != 0, length of bell message */ +static int + bell_len = 0; /* Length of error message */ + + +void +BellOff() +{ + ScreenBuffer a[100]; + int i; + + if (bellwinup) { + unsigned char blank = ' '; + + for (i = 0; i < bell_len; i++) { + a[i].attr = NORMAL; + a[i].data = ' '; + } + } + scrwrite(a, bell_len, 24*80); /* XXX */ +} + + +void +RingBell(s) +char *s; +{ + needToRing = 1; + if (s) { + int i; + ScreenBuffer bellstring[100]; + + bell_len = strlen(s); + bellwinup = 1; + if (bell_len > sizeof bellstring-1) { + OurExitString(stderr, "Bell string too long.", 1); + } + for (i = 0; i < bell_len; i++) { + bellstring[i].attr = STANDOUT; + bellstring[i].data = s[i]; + } + scrwrite(bellstring, bell_len, 24*80); /* XXX */ + } +} + +/* + * Update the OIA area. + */ + +void +ScreenOIA(oia) +OIA *oia; +{ +} + + +/* returns a 1 if no more output available (so, go ahead and block), + or a 0 if there is more output available (so, just poll the other + sources/destinations, don't block). + */ + +int +DoTerminalOutput() +{ + /* called just before a select to conserve IO to terminal */ + if (!(screenInitd||screenStopped)) { + return 1; /* No output if not initialized */ + } + if ((Lowest <= Highest) || needToRing || + (terminalCursorAddress != CorrectTerminalCursor())) { + TryToSend(); + } + if (Lowest > Highest) { + return 1; /* no more output now */ + } else { + return 0; /* more output for future */ + } +} + +/* + * The following are defined to handle transparent data. + */ + +void +TransStop() +{ + RefreshScreen(); +} + +void +TransOut(buffer, count, kind, control) +unsigned char *buffer; +int count; +int kind; /* 0 or 5 */ +int control; /* To see if we are done */ +{ + char *ptr; + + while (DoTerminalOutput() == 0) { + ; + } + for (ptr = buffer; ptr < buffer+count; ptr++) { + *ptr &= 0x7f; /* Turn off parity bit */ + } + (void) DataToTerminal(buffer, count); + if (control && (kind == 0)) { /* Send in AID byte */ + SendToIBM(); + } else { + TransInput(1, kind); /* Go get some data */ + } +} + +/* + * init_screen() + * + * Initialize variables used by screen. + */ + +void +init_screen() +{ + bellwinup = 0; +} + + diff --git a/usr.bin/tn3270/distribution/sys_dos/termout.ext b/usr.bin/tn3270/distribution/sys_dos/termout.ext new file mode 100644 index 0000000..d3c8fb4 --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/termout.ext @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)termout.ext 8.1 (Berkeley) 6/6/93 + */ + +extern void + StartScreen(), + StopScreen(), + ConnectScreen(), + ClearScreen(), + LocalClearScreen(), + RefreshScreen(), + RingBell(), + AddHost(); + +extern int + DoTerminalOutput(); diff --git a/usr.bin/tn3270/distribution/sys_dos/video.h b/usr.bin/tn3270/distribution/sys_dos/video.h new file mode 100644 index 0000000..8fffe6c --- /dev/null +++ b/usr.bin/tn3270/distribution/sys_dos/video.h @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)video.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This is a header file describing the interface via int 10H to the + * video subsystem. + */ + +#define BIOS_VIDEO 0x10 + +typedef enum { + SetMode = 0, + SetCursorType, + SetCursorPosition, + ReadCursorPosition, + ReadLightPenPosition, + SelectActiveDisplayPage, + ScrollActivePageUp, + ScrollActivePageDown, + ReadAttribute_Character, + WriteAttribute_Character, + WriteCharacterOnly, + SetColorPalette, + WriteDot, + ReadDot, + WriteTeletypeToActivePage, + CurrentVideoState, + Reserved16, + Reserved17, + Reserved18, + WriteString +} VideoOperationsType; + +typedef enum { + bw_40x25 = 0, + color_40x25, + bw_80x25, + color_80x25, + color_320x200, + bw_320x200, + bw_640x200, + internal_bw_80x25 +} VideoModeType; diff --git a/usr.bin/tn3270/distribution/telnet/Makefile_ultrix b/usr.bin/tn3270/distribution/telnet/Makefile_ultrix new file mode 100644 index 0000000..dbb93ea --- /dev/null +++ b/usr.bin/tn3270/distribution/telnet/Makefile_ultrix @@ -0,0 +1,179 @@ +# @(#)Makefile 1.4 (Berkeley) 5/15/88 + +# This is the makefile for an Ultrix system. The current Ultrix make(1) doesn't +# support VPATH, so we expand everything out. + +# The following is the telnet makefile for tn3270, using the shared telnet +# sources. + +# +# TERMCAP Define this if your system is termcap based, +# otherwise a terminfo based system is assumed. +# +# SRCRT Includes code to allow you to specify source routes. +# Format is: +# [!]@hop1@hop2...[@|:]dst +# Leading ! means strict source route. +# +# NOSTRNCASECMP Define this if you do not have strncasecmp() in +# your C libarary. +# +# USE_TERMIO Define this if you have System V termio structures. +# What is here is how things are on Cray computers. +# +# KLUDGELINEMODE Define this to get the kludged up version of linemode +# that was in 4.3BSD. This is a good thing to have +# around for talking to older systems. +# + +DEFINES= -DTERMCAP -DSRCRT -DKLUDGELINEMODE + + +VPATH = ../../telnet/Source +XINCLUDES= -I../../telnet/Source +INCLUDES= -I. +XDEFINES = -DTN3270 +OPTIMIZE= -O +CFLAGS = ${OPTIMIZE} ${INCLUDES} ${DEFINES} +XCFLAGS= ${XINCLUDES} ${XDEFINES} +LD = ld +LDFLAGS = -r +PRINT = print +ACTION = sccs tell +LIBC= /lib/libc.a +SD= ../../telnet/Source/ +ALLH= ${SD}defines.h ${SD}externs.h ${SD}fdset.h ${SD}general.h ${SD}ring.h ${SD}types.h +SRCS= ${SD}commands.c ${SD}main.c ${SD}network.c ${SD}ring.c \ + ${SD}sys_bsd.c ${SD}sys_dos.c ${SD}telnet.c ${SD}terminal.c \ + ${SD}tn3270.c ${SD}utilities.c +ALLHC= ${ALLH} ${SRCS} +ALLPRINT = ${ALLHC} +ALLSOURCE= ${ALLHC} Makefile Makefile_ultrix +OBJS= commands.o main.o network.o ring.o sys_bsd.o sys_dos.o \ + telnet.o terminal.o tn3270.o utilities.o + +.c.o: + ${CC} -c ${CFLAGS} ${XCFLAGS} $< + +telprog.o: ${OBJS} ${LIBC} + ${LD} ${LDFLAGS} -o $@ ${OBJS} + +clean: FRC + rm -f ${OBJS} core telnet + +depend: FRC ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +lint: FRC ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: FRC ${ALLHC} + ctags ${ALLHC} + +print: FRC ${ALLPRINT} + ${PRINT} ${ALLPRINT} + +commands.o: ${SD}commands.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}commands.c + +main.o: ${SD}main.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}main.c + +network.o: ${SD}network.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}network.c + +ring.o: ${SD}ring.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}ring.c + +sys_bsd.o: ${SD}sys_bsd.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}sys_bsd.c + +sys_dos.o: ${SD}sys_dos.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}sys_dos.c + +telnet.o: ${SD}telnet.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}telnet.c + +terminal.o: ${SD}terminal.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}terminal.c + +tn3270.o: ${SD}tn3270.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}tn3270.c + +utilities.o: ${SD}utilities.c + ${CC} -c ${CFLAGS} ${XCFLAGS} ${SD}utilities.c + + +action: FRC + ${ACTION} + +clist: FRC ${SRCS} + @for i in ${SRCS} ; \ + do (echo ${DIRPATH}$$i); done + +hclist: FRC ${ALLHC} + @for i in ${ALLHC} ; \ + do (echo ${DIRPATH}$$i); done + +sourcelist: FRC ${ALLSOURCE} + @for i in ${ALLSOURCE} ../../telnet/Makefile ; \ + do (echo ${DIRPATH}$$i); done + +FRC: + +# DO NOT DELETE THIS LINE -- mkdep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + +commands.o: ../../telnet/Source/commands.c /usr/include/sys/types.h +commands.o: /usr/include/sys/socket.h /usr/include/netinet/in.h +commands.o: /usr/include/signal.h /usr/include/machine/trap.h +commands.o: /usr/include/netdb.h /usr/include/ctype.h +commands.o: /usr/include/arpa/telnet.h ../../telnet/Source/ring.h +commands.o: ../../telnet/Source/externs.h /usr/include/stdio.h +commands.o: /usr/include/setjmp.h ../../telnet/Source/defines.h +commands.o: ../../telnet/Source/types.h +main.o: ../../telnet/Source/main.c /usr/include/sys/types.h +main.o: ../../telnet/Source/ring.h ../../telnet/Source/externs.h +main.o: /usr/include/stdio.h /usr/include/setjmp.h +main.o: ../../telnet/Source/defines.h +network.o: ../../telnet/Source/network.c /usr/include/sys/types.h +network.o: /usr/include/sys/socket.h /usr/include/sys/time.h +network.o: /usr/include/time.h /usr/include/errno.h /usr/include/arpa/telnet.h +network.o: ../../telnet/Source/ring.h ../../telnet/Source/defines.h +network.o: ../../telnet/Source/externs.h /usr/include/stdio.h +network.o: /usr/include/setjmp.h ../../telnet/Source/fdset.h +ring.o: ../../telnet/Source/ring.c /usr/include/stdio.h /usr/include/errno.h +ring.o: /usr/include/sys/types.h /usr/include/sys/ioctl.h +ring.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h +ring.o: /usr/include/sys/socket.h ../../telnet/Source/ring.h +ring.o: ../../telnet/Source/general.h +sys_bsd.o: ../../telnet/Source/sys_bsd.c /usr/include/sys/ioctl.h +sys_bsd.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h +sys_bsd.o: /usr/include/sys/types.h /usr/include/sys/time.h /usr/include/time.h +sys_bsd.o: /usr/include/sys/socket.h /usr/include/signal.h +sys_bsd.o: /usr/include/machine/trap.h /usr/include/errno.h +sys_bsd.o: ../../telnet/Source/ring.h ../../telnet/Source/fdset.h +sys_bsd.o: ../../telnet/Source/defines.h ../../telnet/Source/externs.h +sys_bsd.o: /usr/include/stdio.h /usr/include/setjmp.h +sys_bsd.o: ../../telnet/Source/types.h +sys_dos.o: ../../telnet/Source/sys_dos.c +telnet.o: ../../telnet/Source/telnet.c /usr/include/sys/types.h +telnet.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h +telnet.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h +telnet.o: /usr/include/sys/ttydev.h /usr/include/arpa/telnet.h +telnet.o: /usr/include/strings.h ../../telnet/Source/ring.h +telnet.o: ../../telnet/Source/defines.h ../../telnet/Source/externs.h +telnet.o: /usr/include/stdio.h /usr/include/setjmp.h +telnet.o: ../../telnet/Source/types.h ../../telnet/Source/general.h +telnet.o: /usr/include/varargs.h +terminal.o: ../../telnet/Source/terminal.c /usr/include/arpa/telnet.h +terminal.o: /usr/include/sys/types.h ../../telnet/Source/ring.h +terminal.o: ../../telnet/Source/externs.h /usr/include/stdio.h +terminal.o: /usr/include/setjmp.h ../../telnet/Source/types.h +tn3270.o: ../../telnet/Source/tn3270.c ../../telnet/Source/fdset.h +utilities.o: ../../telnet/Source/utilities.c /usr/include/arpa/telnet.h +utilities.o: /usr/include/sys/types.h /usr/include/ctype.h +utilities.o: ../../telnet/Source/ring.h ../../telnet/Source/externs.h +utilities.o: /usr/include/stdio.h /usr/include/setjmp.h + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/usr.bin/tn3270/distribution/ultrix.curses b/usr.bin/tn3270/distribution/ultrix.curses new file mode 100644 index 0000000..f5fcd94 --- /dev/null +++ b/usr.bin/tn3270/distribution/ultrix.curses @@ -0,0 +1,46 @@ +Return-Path: mtxinu!kinetics!minshall@ucbvax.Berkeley.EDU +Received: from ucbvax.berkeley.edu + by violet.berkeley.edu (5.54 (CFC 4.22.3)/1.16.17l) + id AA23846; Wed, 30 Mar 88 19:54:24 PST +Received: by ucbvax.berkeley.edu (5.59/1.26) + id AA09851; Tue, 29 Mar 88 23:25:19 PST +Received: by mtxinu.UUCP (5.51/4.7) + id AA05135; Tue, 29 Mar 88 17:32:01 PST +Message-Id: <8803300132.AA05135@mtxinu.UUCP> +Date: Thu, 17 Mar 88 11:06:10 pst +From: mtxinu!kinetics!minshall@ucbvax.Berkeley.EDU (Greg Minshall) +To: mtxinu!minshall + +Path: kinetics!zehntel!varian!ptsfa!pacbell!ames!ll-xn!husc6!panda!teddy!jpn +From: jpn@teddy.UUCP (John P. Nelson) +Newsgroups: comp.bugs.4bsd +Subject: Re: Ultrix curses problem +Keywords: curses ultrix bug fix +Message-ID: <4668@teddy.UUCP> +Date: 14 Mar 88 19:43:39 GMT +References: <535@hscfvax.harvard.edu> +Reply-To: jpn@teddy.UUCP (John P. Nelson) +Organization: GenRad, Inc., Concord, Mass. +Lines: 21 + +>I have found the bug, fixable as above, in both Ultrix 1.2 and 2.0. Feedback +>from those brave souls who have brought up 2.2 would be most welcome. + +Yup, the bug exists in Ultrix 2.2 as well. I have reported this bug to +DEC support every time we get a new release. I assume that my bug reports +are getting filed (in the circular file). + +It is clear that whoever made this "fix" at DEC had no understanding +of curses whatsoever. As in the earlier posting, the bug can be fixed +by replacing the definitions of the nl() and nonl() macros in curses.h with: + +#define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) +#define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) + +- john nelson. + +P.S. I did reach someone at DEC who would listen (Thanks Chet!) My + understanding is that they have no plans to fix this bug, as curses + is now "owned" by some group in England, who is working on a port of the + terminfo curses for Ultrix 2.4. I'm just pissed that my bug reports + submitted for Ultrix 1.2 and 2.0 were ignored. diff --git a/usr.bin/tn3270/distribution/utilities/adm3a.keys b/usr.bin/tn3270/distribution/utilities/adm3a.keys new file mode 100644 index 0000000..4e65374 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/adm3a.keys @@ -0,0 +1,78 @@ +1LSI ADM 3A Key Definitions for IBM 3277 Terminal Emulation 06/18/81 ++LSI ADM 3A Key Definitions for IBM 3277 Terminal Emulation 06/18/81 + + 3277 Key ADM Key(s) | 3277 Key LSI ADM 3A Key(s) + ======== ========== | ======== ==================== + | + Cursor Movement Keys | Command Keys ++______ ________ ____ _______ ____ + | + New Line Ctrl-N -or- | Enter Return + Home | Clear Ctrl-Z + Tab Ctrl-I | + Back Tab Ctrl-B | Program Function Keys ++ _______ ________ ____ + Cursor Left Ctrl-H | + Cursor Right Ctrl-L | PF1 Esc 1 + Cursor Up Ctrl-K | PF2 Esc 2 + Cursor Down Ctrl-J -or- | PF3 Esc 3 + Line Feed | PF4 Esc 4 + Home Ctrl-@ | PF5 Esc 5 + | PF6 Esc 6 + | PF7 Esc 7 + Edit Control Keys | PF8 Esc 8 ++____ _______ ____ + | PF9 Esc 9 + Delete Char Ctrl-D -OR- Rub | PF10 Esc 0 + Erase EOF Ctrl-E | PF11 Esc Colon + Erase Input Ctrl-W | PF12 Esc Minus + Insert Mode Esc Space | PF13 Ctrl-F 1 3 + End Insert Esc Space | PF14 Ctrl-F 1 4 + Dup Ctrl-U | PF15 Ctrl-F 1 5 + Field Mark Ctrl-Y | PF16 Ctrl-F 1 6 + | PF17 Ctrl-F 1 7 + Series-1 Control Keys | PF18 Ctrl-F 1 8 ++________ _______ ____ + | PF19 Ctrl-F 1 9 + Reset After Error Ctrl-R | PF20 Ctrl-F 2 0 + Keyboard Unlock Ctrl-T | PF21 Ctrl-F 2 1 + Purge Input Buffer Ctrl-X | PF22 Ctrl-F 2 2 + Stop Output Ctrl-S | PF23 Ctrl-F 2 3 + Start Output Ctrl-Q | PF24 Ctrl-F 2 4 + Re-Display Screen Ctrl-V | + | Program Attention Keys ++ _______ _________ ____ + Miscellaneous 3277 Keys | ++_____________ ____ ____ + | PA1 Ctrl-P 1 + Cursor Select Esc Period | PA2 Ctrl-P 2 + Test Request (not supported) | PA3 Ctrl-P 3 + + Series 1 Local Editing Keys ++______ _ _____ _______ ____ + + Set Tab Stop Esc Semicolon + Clear (all) Tab Stops Esc Plus + Set Left Margin (New Line) Esc LeftParen + Set Home (Home) Esc Exclamation + Tab to Next Local Tab Stop Esc i (or Esc I) + Tab to Previous Local Tab Stop Esc b (or Esc B) + Indent (to Next Local Tab Stop - New Line) Esc l (or Esc L) + Undent (to Previous Local Tab Stop - New Line) Esc h (or Esc H) + + + Note: If the terminal hangs up, enter "Ctrl-H" and see if the + cursor moves. If it does, you are trying to enter data + into a protected field, trying to insert a character when + the last character of the field is non-blank, or trying to + communicate to a virtual process which is not accepting data. + If the cursor did not move, a transmission error or terminal + lock has occurred. Enter the following sequence to unhang + the terminal: "Ctrl-R Ctrl-T Ctrl-X Ctrl-Q Ctrl-V". + + ********** DRAFT ONLY - SPECIFICATION SUBJECT TO CHANGE ********** ++********** DRAFT ONLY - SPECIFICATION SUBJECT TO CHANGE ********** ++********** DRAFT ONLY - SPECIFICATION SUBJECT TO CHANGE ********** ++********** DRAFT ONLY - SPECIFICATION SUBJECT TO CHANGE ********** + + diff --git a/usr.bin/tn3270/distribution/utilities/cross.c b/usr.bin/tn3270/distribution/utilities/cross.c new file mode 100644 index 0000000..191aac0 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/cross.c @@ -0,0 +1,55 @@ +/* + This program is, essentially, a cross product generator. It takes + an input file which is said to consist of a number of lines, and + expands each line. A line like + (a,b)(c,d) + will be expanded to lines like + ac + ad + bc + bd + (without regard for the ORDER of the output; ie: the lines can appear + in any order). + + Parenthesis can be nested, so + (a,b)(c(d,e),f) + will produce + acd + ace + af + bcd + bce + bf + */ + + +#include + +char leftParen, /* The left parenthesis character */ + rightParen; /* The right parenthesis character */ + + +/* Finds next occurrence of 'character' at this level of nesting. + Returns 0 if no such character found. + */ + +char * +ThisLevel(string, character) +char *string, character; +{ + int level; /* Level 0 is OUR level */ + + level = 0; + + while (*string != '\0') { + if (*string == leftParen) + level++; + else if (*string == rightParen) { + level--; + if (level < 0) + return(0); + } + if ((level == 0) && (*string == character)) + return(string); + string++; + } diff --git a/usr.bin/tn3270/distribution/utilities/makefile b/usr.bin/tn3270/distribution/utilities/makefile new file mode 100644 index 0000000..0cb5b3e --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/makefile @@ -0,0 +1,121 @@ +# +# Copyright (c) 1988 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# @(#)makefile 8.1 (Berkeley) 6/6/93 +# +# msdos versus unix defines +O = .o +#PC_O = .obj + +X = +#PC_X = .exe + +L = +#PC_L = -link + +CC = cc +#PC_CC = cl + +MV = mv +#PC_MV = rename + +RM = rm -f +#PC_RM= erase + +LINT_ARGS = +#PC_LINT_ARGS = -DLINT_ARGS + +DEBUG_FLAGS = -g +#PC_DEBUG_FLAGS = -Zi -Od + +AR = ar +AR1 = cr +AR2 = +AR3 = +#PC_AR = lib +#PC_AR1 = +#PC_AR2 = + +#PC_AR3 = ";" + +RANLIB = ranlib +#PC_RANLIB = echo "Done with " + +DEFINES = ${LINT_ARGS} + +CFLAGS = ${DEBUG_FLAGS} -I.. + +PRINT = lpr -p + +ALLC = tnrecv.c +ALLH = tncomp.h + +ALLPRINT = ${ALLH} ${ALLC} + +ALLSOURCE = ${ALLPRINT} makefile makefile.mak + +ALLO = tnrecv$O + +.c.obj: + ${CC} ${CFLAGS} -c $< + +all: tnrecv$X + +tnrecv$X: tnrecv$O + ${CC} ${CFLAGS} -o $@ tnrecv$O $L ../api/apilib.a + +clean: + for i in makefile.bak ${ALLO} errs tnrecv$X; \ + do (${RM} $$i); done + +.DEFAULT: + sccs get $< + +sccsclean: + -sccs clean + -sccs get makefile + +action: + ${ACTION} + +print: + ${PRINT} ${ALLPRINT} + +sourcelist: ${ALLSOURCE} tarread.exe + @for i in ${ALLSOURCE} tarread.exe; \ + do (echo ${DIRPATH}$$i); done + +depend: + grep '^#include' ${ALLC} | grep -v '<' | \ + sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' \ + -e 's/\.c/$$O/' | \ + awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \ + else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ + else rec = rec " " $$2 } } \ + END { print rec } ' > makedep + echo '$$r makedep' >>eddep + echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep + echo '$$r makedep' >>eddep + echo 'w' >>eddep + -rm -f makefile.bak + cp makefile makefile.bak + ed - makefile < eddep + rm eddep makedep + +# DO NOT DELETE THIS LINE + +#include "tncomp.h" "../api/api.h" "../ctlr/function.h" "../ctlr/hostctlr.h" +#include "../ctlr/oia.h" "../ctlr/screen.h" "../apilib/disp_asc.h" +#include "../apilib/astosc.h" "../general/general.h" diff --git a/usr.bin/tn3270/distribution/utilities/srccmd/tar/makefile b/usr.bin/tn3270/distribution/utilities/srccmd/tar/makefile new file mode 100644 index 0000000..f4618af --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/srccmd/tar/makefile @@ -0,0 +1,8 @@ +tarread.obj: tarread.c + cl /c /Zd tarread.c + +tarread.exe: tarread.obj + link tarread,,tarread/map/lin; + +tarread.sym: tarread.map + mapsym /l tarread diff --git a/usr.bin/tn3270/distribution/utilities/srccmd/tar/tar.h b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tar.h new file mode 100644 index 0000000..0345756 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tar.h @@ -0,0 +1,19 @@ +/* tar.h */ + +#define TBLOCK 512 +#define NAMSIZ 100 + +union hblock { + char dummy[TBLOCK]; + struct header { + char name[NAMSIZ]; + char mode[8]; + char gid[8]; + char uid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + } dbuf; +}; diff --git a/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c new file mode 100644 index 0000000..fedeb69 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/srccmd/tar/tarread.c @@ -0,0 +1,208 @@ +/* tarread.c */ +/* Copyright (c) 1985, by Carnegie-Mellon University */ + +#include +#include +#include +#include +#include "tar.h" + +char usage[] = "tarread: usage: tarread tx[vwz] tarfile\n"; +union hblock hbuf; + +int verbose = 0; +int confirm = 0; +int binary = 0; +char cmd; + +main(argc, argv) +int argc; +char *argv[]; +{ + FILE *fp; + char *cp; + + if (argc != 3) { + fprintf(stderr, usage); + exit(1); + } + + for (cp = argv[1]; *cp; cp++) + switch (*cp) { + case 't': + case 'x': + cmd = *cp; + break; + + case 'v': + verbose++; + break; + case 'z': + binary++; + break; + case 'w': + confirm++; + break; + default: + fprintf(stderr, "tarread: unknown switch %c\n", *cp); + fprintf(stderr, usage); + exit(1); + } + + if ((fp = fopen(argv[2], "rb")) == NULL) { + fprintf(stderr, "tarrread: cannot open %s\n", argv[2]); + exit(1); + } + + for (;;) { + if (fread(&hbuf, sizeof(hbuf), 1, fp) != 1) { + perror("fread"); + exit(1); + } + if (!proc_file(fp)) + break; + } +} + + +int proc_file(fp) +FILE *fp; +{ + char name[NAMSIZ]; + unsigned short mode; + short uid, gid; + long size, mtime; + char c; + int confrmd; + long skip; + + if (hbuf.dbuf.name[0] == '\0') + return (NULL); + + strcpy(name, hbuf.dbuf.name); + if (sscanf(hbuf.dbuf.mode, "%o", &mode) != 1) + fprintf("Couldn't read mode\n"); + if (sscanf(hbuf.dbuf.uid, "%o", &uid) != 1) + fprintf("Couldn't read uid\n"); + if (sscanf(hbuf.dbuf.gid, "%o", &gid) != 1) + fprintf("Couldn't read gid\n"); + if (sscanf(hbuf.dbuf.size, "%12lo %12lo", &size, &mtime) != 2) + fprintf("Couldn't read size or mtime\n"); + + skip = (size + TBLOCK - 1) / TBLOCK * TBLOCK; + + switch (cmd) { + case 't': + if (verbose) + printf("%8o %d/%d\t %6ld %.24s %s\n", mode, + uid, gid, size, ctime(&mtime), name); + else + printf("%s\n", name); + + break; + + case 'x': + if (verbose) + printf("x %s: ", name); + confrmd = 1; + + if (confirm) { + confrmd = 0; + if ((c = getchar()) == 'y') + confrmd++; + while (c != '\n') + c = getchar(); + if(!confrmd) + break; + } + + if(extract(name, size, mode, mtime, fp)) + skip = 0; + + if (verbose) + printf("\n"); + break; + } + if (fseek(fp, skip, 1)) { + perror("fseek"); + exit(1); + } + return (1); +} + + +int extract(fname, size, mode, mtime, ifp) +char *fname; +long size; +unsigned short mode; +long mtime; +FILE *ifp; +{ + FILE *ofp; + char fbuf[TBLOCK]; + long copied, left; + char *s, *np, *strchr(); + struct stat sbuf; + + for(np = fname; s = strchr(np, '/'); np = s+1) { + *s = '\0'; + if(stat(fname, &sbuf)) { + if(mkdir(fname)) + perror("mkdir"); + } else if(!(sbuf.st_mode & S_IFDIR)) { + fprintf(stderr, "\n%s: Not a directory", fname); + *s = '/'; + fprintf(stderr, "\ntar: %s - cannot create", fname); + return (0); + } + *s = '/'; + } + if(!*np) + return (0); + + if (binary) { + if ((ofp = fopen(fname, "wb")) == NULL) { + perror("extract:"); + return (0); + } + } else { + if ((ofp = fopen(fname, "w")) == NULL) { + perror("extract:"); + return (0); + } + } + + for(copied = 0; copied < size; copied += TBLOCK) { + if(fread(fbuf, TBLOCK, 1, ifp) != 1) { + perror("fread"); + exit(1); + } + left = size - copied; + if(fwrite(fbuf, (int)min(left, TBLOCK), 1, ofp) != 1) { + perror("fwrite"); + exit(1); + } + } + + if(fclose(ofp)) { + perror("fclose"); + exit(1); + } + + /* + * Now, set modification time. + */ + { +#include + struct utimbuf utim; + + utim.modtime = mtime; + + if (utime(fname, &utim) == -1) { + perror("utime"); + exit(1); + } + } + + return (1); +} diff --git a/usr.bin/tn3270/distribution/utilities/tncomp.h b/usr.bin/tn3270/distribution/utilities/tncomp.h new file mode 100644 index 0000000..c726297 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/tncomp.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)tncomp.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Where the fields fall on the formatted screen used by tncomp, tnrecv, + * and tnsend. + */ + +#define SEND_SEQUENCE 1 +#define SEND_SEQUENCE_LENGTH 23 + +#define ACK_SEQUENCE (SEND_SEQUENCE+SEND_SEQUENCE_LENGTH+1) +#define ACK_SEQUENCE_LENGTH 22 + +#define CHECKSUM (ACK_SEQUENCE+ACK_SEQUENCE_LENGTH+1) +#define CHECKSUM_LENGTH 32 + +#define DATA (CHECKSUM+CHECKSUM_LENGTH+1) +#define DATA_LENGTH ((80*22)+79) diff --git a/usr.bin/tn3270/distribution/utilities/tnrecv.c b/usr.bin/tn3270/distribution/utilities/tnrecv.c new file mode 100644 index 0000000..4474691 --- /dev/null +++ b/usr.bin/tn3270/distribution/utilities/tnrecv.c @@ -0,0 +1,674 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tnrecv.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#include + +#include "tncomp.h" + + +#include "../ctlr/api.h" +#include "../ctlr/function.h" +#include "../ctlr/hostctlr.h" +#include "../ctlr/oia.h" +#include "../ctlr/screen.h" + +#include "../api/disp_asc.h" +#include "../api/astosc.h" + +#include "../general/general.h" + +ScreenImage Host[MAXSCREENSIZE]; + +static char + a_send_sequence[SEND_SEQUENCE_LENGTH+1], + a_ack_sequence[ACK_SEQUENCE_LENGTH+1], + a_checksum[CHECKSUM_LENGTH+1], + data_array[DATA_LENGTH+1]; + +static int + verbose, + blocks, + enter_index, + clear_index, + ScreenSize, + session_id; + +static unsigned int + send_sequence, + ack_sequence = -1, + checksum; + +api_perror(string) +char *string; +{ + fprintf(stderr, "Error: [0x%x/0x%x:0x%x/0x%x] from %s.\n", + api_sup_fcn_id, api_sup_errno, + api_fcn_fcn_id, api_fcn_errno, string); +} + + +char * +session_type(type) +int type; +{ + switch (type) { + case TYPE_WSCTL: + return "work station control"; + case TYPE_DFT: + return "distributed function terminal"; + case TYPE_CUT: + return "control unit terminal"; + case TYPE_NOTEPAD: + return "notepad"; + case TYPE_PC: + return "personal computer"; + default: + return "(UNKNOWN)"; + } +} + +static int +wait_for_ps_or_oia() +{ +#if defined(unix) + return api_ps_or_oia_modified(); +#endif /* defined(unix) */ +} + + +static int +wait_for_unlock() +{ + OIA oia; + ReadOiaGroupParms re; + static char zeroes[sizeof oia.input_inhibited] = { 0 }; + + do { + re.rc = re.function_id = 0; + re.session_id = session_id; + re.oia_buffer = (char far *) &oia; + re.oia_group_number = API_OIA_ALL_GROUPS; + if (api_read_oia_group(&re) == -1) { + api_perror("api_read_oia_group"); + return -1; + } else if (verbose) { + if (IsOiaReady3274(&oia)) { + printf("3274 ready, "); + } + if (IsOiaMyJob(&oia)) { + printf("my job, "); + } + if (IsOiaInsert(&oia)) { + printf("insert mode, "); + } + if (IsOiaSystemLocked(&oia)) { + printf("system locked, "); + } + if (IsOiaTWait(&oia)) { + printf("terminal wait, "); + } + printf("are some bits from the OIA.\n"); + } + /* We turned this on, so turn it off now */ + ResetOiaApiInhibit(&oia); + if (memcmp(zeroes, oia.input_inhibited, sizeof oia.input_inhibited)) { + if (wait_for_ps_or_oia() == -1) { + return -1; + } + } + } while (memcmp(zeroes, oia.input_inhibited, sizeof oia.input_inhibited)); + return 0; +} + +static int +initialize() +{ + QuerySessionIdParms id; + QuerySessionParametersParms pa; + QuerySessionCursorParms cu; + ConnectToKeyboardParms conn; + DisableInputParms disable; + NameArray namearray; + + if (api_init() == 0) { + fprintf(stderr, "API function not available.\n"); + return -1; + } + + id.rc = 0; + id.function_id = 0; + id.option_code = ID_OPTION_BY_NAME; + id.data_code = 'E'; + id.name_array = &namearray; + namearray.length = sizeof namearray; + if (api_query_session_id(&id)) { + api_perror("api_query_session_id"); + } else if (namearray.number_matching_session == 0) { + fprintf(stderr, "query_session_id: No matching sessions!\n"); + return -1; + } else if (verbose) { + printf("Session short name 0x%x, type is ", + namearray.name_array_element.short_name); + printf("%s", session_type(namearray.name_array_element.type)); + printf(", session ID is: 0x%x\n", + namearray.name_array_element.session_id); + } + session_id = namearray.name_array_element.session_id; + + pa.rc = pa.function_id = 0; + pa.session_id = session_id; + if (api_query_session_parameters(&pa) == -1) { + api_perror("api_query_session_parameters"); + return -1; + } else if (verbose) { + printf("Session type %s, ", session_type(pa.session_type)); + if (pa.session_characteristics&CHARACTERISTIC_EAB) { + printf(" has EAB, "); + } + if (pa.session_characteristics&CHARACTERISTIC_PSS) { + printf(" has PSS, "); + } + printf("%d rows, %d columns ", pa.rows, pa.columns); + if (pa.presentation_space) { + printf("presentation space at 0x%x:0x%x.\n", + FP_SEG(pa.presentation_space), FP_OFF(pa.presentation_space)); + } else { + printf("(no direct presentation space access).\n"); + } + } + ScreenSize = pa.rows*pa.columns; + if (pa.session_characteristics&CHARACTERISTIC_EAB) { + fprintf(stderr, + "tncomp utilities not designed to work with extended attribute buffers.\n"); + return -1; + } + + if (verbose) { + cu.rc = cu.function_id = 0; + cu.session_id = session_id; + if (api_query_session_cursor(&cu) == -1) { + api_perror("api_query_session_cursor"); + } else { + printf("cursor"); + if (cu.cursor_type&CURSOR_INHIBITED_AUTOSCROLL) { + printf(" inhibited autoscroll"); + } + if (cu.cursor_type&CURSOR_INHIBITED) { + printf(" inhibited"); + } + if (cu.cursor_type&CURSOR_BLINKING) { + printf(" blinking"); + } else { + printf(" not blinking"); + } + if (cu.cursor_type&CURSOR_BOX) { + printf(" box "); + } else { + printf(" not box "); + } + printf("at row %d, column %d.\n", + cu.row_address, cu.column_address); + } + } + + conn.rc = conn.function_id = 0; + conn.session_id = session_id; + conn.event_queue_id = conn.input_queue_id = 0; + conn.intercept_options = 0; + if (api_connect_to_keyboard(&conn) == -1) { + api_perror("api_connect_to_keyboard"); + } else if (verbose) { + if (conn.first_connection_identifier) { + printf("First keyboard connection.\n"); + } else { + printf("Not first keyboard connection.\n"); + } + } + + disable.rc = disable.function_id = 0; + disable.session_id = session_id; + disable.connectors_task_id = 0; + if (api_disable_input(&disable) == -1) { + api_perror("api_disable_input"); + return -1; + } else if (verbose) { + printf("Disabled.\n"); + } + + if ((enter_index = ascii_to_index("ENTER")) == -1) { + return -1; + } + if ((clear_index = ascii_to_index("CLEAR")) == -1) { + return -1; + } + + return 0; /* all ok */ +} + +static int +send_key(index) +int index; +{ + WriteKeystrokeParms wr; + extern struct astosc astosc[]; + + wait_for_unlock(); + + wr.rc = wr.function_id = 0; + wr.session_id = session_id; + wr.connectors_task_id = 0; + wr.options = OPTION_SINGLE_KEYSTROKE; + wr.number_of_keys_sent = 0; + wr.keystroke_specifier.keystroke_entry.scancode = astosc[index].scancode; + wr.keystroke_specifier.keystroke_entry.shift_state + = astosc[index].shiftstate; + if (api_write_keystroke(&wr) == -1) { + api_perror("api_write_keystroke"); + return -1; + } else if (wr.number_of_keys_sent != 1) { + fprintf(stderr, "write_keystroke claims to have sent %d keystrokes.\n", + wr.number_of_keys_sent); + return -1; + } else if (verbose) { + printf("Keystroke sent.\n"); + } + if (wait_for_ps_or_oia() == -1) { + return -1; + } + return 0; +} + +static int +terminate() +{ + EnableInputParms enable; + DisconnectFromKeyboardParms disc; + + enable.rc = enable.function_id = 0; + enable.session_id = session_id; + enable.connectors_task_id = 0; + if (api_enable_input(&enable) == -1) { + api_perror("api_enable"); + return -1; + } else if (verbose) { + printf("Enabled.\n"); + } + + disc.rc = disc.function_id = 0; + disc.session_id = session_id; + disc.connectors_task_id = 0; + if (api_disconnect_from_keyboard(&disc) == -1) { + api_perror("api_disconnect_from_keyboard"); + return -1; + } else if (verbose) { + printf("Disconnected from keyboard.\n"); + } + + (void) api_finish(); + + return 0; +} + + +static int +get_screen() +{ + CopyStringParms copy; + /* Time copy services */ + + wait_for_unlock(); + + copy.copy_mode = 0; + copy.rc = copy.function_id = 0; + copy.source.session_id = session_id; + copy.source.buffer = 0; + copy.source.characteristics = 0; + copy.source.session_type = TYPE_DFT; + copy.source.begin = 0; + + copy.source_end = ScreenSize; + + copy.target.session_id = 0; + copy.target.buffer = (char *) &Host[0]; + copy.target.characteristics = 0; + copy.target.session_type = TYPE_DFT; + + if (api_copy_string(©) == -1) { + api_perror("api_copy_string"); + return -1; + } + return 0; +} + + +put_at(offset, from, length, attribute) +int offset; +char *from; +int length; +{ + CopyStringParms copy; + + wait_for_unlock(); + + copy.copy_mode = 0; + copy.rc = copy.function_id = 0; + copy.source.session_id = 0; + copy.source.buffer = from; + copy.source.characteristics = 0; + copy.source.session_type = TYPE_DFT; + copy.source.begin = 0; + + copy.source_end = length-1; + + copy.target.session_id = session_id; + copy.target.buffer = 0; + copy.target.characteristics = 0; + copy.target.session_type = TYPE_DFT; + copy.target.begin = offset; + + if (api_copy_string(©) == -1) { + api_perror("api_copy_string"); + return -1; + } + return 0; +} + +static void +translate(input, output, table, length) +char *input, *output, table[]; +int length; +{ + unsigned char *indices = (unsigned char *) input; + + while (length--) { + *output++ = table[*indices++]; + } +} + +static int +find_input_area(from) +int from; +{ +#define FieldDec(p) (0) /* We don't really use this */ + register int i, attr; + + for (i = from; i < MAXSCREENSIZE; ) { + if (IsStartField(i)) { + attr = FieldAttributes(i); + i++; + if (!IsProtectedAttr(i, attr)) { + return i; + } + } else { + i++; + } + } + return -1; +} + + +static void +getascii(offset, to, length) +int offset; /* Where in screen */ +char *to; /* Where it goes to */ +int length; /* Where to put it */ +{ + translate(Host+offset, to, disp_asc, length); +} + +static int +putascii(offset, from, length, before) +int offset; /* Where in screen */ +char *from; /* Where it comes from */ +int length; /* Where to put it */ +int before; /* How much else should go */ +{ + translate(from, Host+offset, asc_disp, length); + if (put_at(offset-before, + (char *) Host+offset-before, length+before) == -1) { + return -1; + } + return 0; +} + +static int +ack() +{ + static char ack_blanks[sizeof a_ack_sequence] = {0}; + + if (ack_blanks[0] == 0) { + int i; + + for (i = 0; i < sizeof ack_blanks; i++) { + ack_blanks[i] = ' '; + } + } + + memcpy(a_ack_sequence, ack_blanks, sizeof a_ack_sequence); + sprintf(a_ack_sequence, "%d", ack_sequence); + a_ack_sequence[strlen(a_ack_sequence)] = ' '; + if (putascii(ACK_SEQUENCE, a_ack_sequence, ACK_SEQUENCE_LENGTH, 0) == -1) { + return -1; + } + return 0; +} + +static int +formatted_correct() +{ + if ((find_input_area(SEND_SEQUENCE-1) != SEND_SEQUENCE) || + (find_input_area(SEND_SEQUENCE) != ACK_SEQUENCE) || + (find_input_area(ACK_SEQUENCE) != CHECKSUM) || + (find_input_area(CHECKSUM) != DATA)) { + return -1; + } else { + return 0; + } +} + + +main(argc, argv) +int argc; +char *argv[]; +{ + register int i; + int data_length, input_length; + char ascii[8]; /* Lots of room */ + FILE *outfile; + char *data; + char *argv0 = argv[0]; + + argc--; + argv++; + /* Process any flags */ + while (argc && (argv[0][0] == '-')) { + switch (argv[0][1]) { + case 'v': + verbose = 1; + break; + case 'b': + blocks = 1; + break; + } + argc--; + argv++; + } + + if ((argc) < 2) { + fprintf(stderr, + "usage: %s [-b] [-v] local.file remote.file [remote.options]\n", + argv0); + exit(1); + } + + /* Open the local file */ + if ((outfile = fopen(argv[0], "w")) == NULL) { + perror("fopen"); + exit(2); + } + argc--; + argv++; + + if (initialize() == -1) { + return -1; + } + + /* build the command line */ + data = data_array; + strcpy(data, "TNCOMP SEND"); + data += strlen(data); + while (argc--) { + *data++ = ' '; + strcpy(data, argv[0]); + data += strlen(argv[0]); + argv++; + } + if (verbose) { + printf("%s\n", data_array); + } + if (get_screen() == -1) { + return -1; + } + data_length = strlen(data_array); + if ((i = find_input_area(0)) == -1) { /* Get an input area */ + if (send_key(clear_index) == -1) { + return -1; + } + if ((i = find_input_area(0)) == -1) { /* Try again */ + fprintf(stderr, "Unable to enter command line.\n"); + return -1; + } + } + if (putascii(i, data_array, data_length, 0) == -1) { + return -1; + } + if (send_key(enter_index) == -1) { + return -1; + } + do { + if (get_screen() == -1) { + return -1; + } + } while (formatted_correct() == -1); + + do { + if (get_screen() == -1) { + return -1; + } + /* For each screen */ + if (formatted_correct() == -1) { + fprintf(stderr, "Bad screen written by host.\n"); + return -1; + } + /* If MDT isn't reset in the sequence number, go around again */ + if (Host[ACK_SEQUENCE-1]&ATTR_MDT) { + if (wait_for_ps_or_oia() == -1) { + return -1; + } + continue; + } + getascii(SEND_SEQUENCE, a_send_sequence, SEND_SEQUENCE_LENGTH); + send_sequence = atoi(a_send_sequence); + getascii(CHECKSUM, a_checksum, CHECKSUM_LENGTH); + checksum = atoi(a_checksum); + getascii(DATA, data_array, DATA_LENGTH); + data = data_array; + if (send_sequence != (ack_sequence+1)) { + if (ack() == -1) { + return -1; + } + data = "1234"; /* Keep loop from failing */ + if (send_key(enter_index) == -1) { + return -1; + } + if (get_screen() == -1) { + return -1; + } + continue; + } + + data_length = DATA_LENGTH; + while (data_length && memcmp(data, " EOF", 4) + && memcmp(data, " ", 4)) { + memcpy(ascii, data, 4); + data += 4; + data_length -= 4; + ascii[4] = 0; + input_length = atoi(ascii); + /* CMS can't live with zero length records */ + if ((input_length > 1) || + ((input_length == 1) && (data[0] != ' '))) { + if (fwrite(data, sizeof (char), + input_length, outfile) == 0) { + perror("fwrite"); + exit(9); + } + } + fprintf(outfile, "\n"); + data += input_length; + data_length -= input_length; + } + + ack_sequence = send_sequence; + if (blocks) { + printf("#"); + fflush(stdout); + } + if (ack() == -1) { + return -1; + } + if (send_key(enter_index) == -1) { + return -1; + } + } while (memcmp(data, " EOF", 4)); + + if (blocks) { + printf("\n"); + } + if (terminate() == -1) { + return -1; + } + return 0; +} diff --git a/usr.bin/tn3270/general/genbsubs.c b/usr.bin/tn3270/general/genbsubs.c new file mode 100644 index 0000000..b5377a6 --- /dev/null +++ b/usr.bin/tn3270/general/genbsubs.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)genbsubs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* The output of bunequal is the offset of the byte which didn't match; + * if all the bytes match, then we return n. + * bunequal(s1, s2, n) */ + +int +bunequal(s1, s2, n) +register char *s1, *s2; +register n; +{ + register int i = 0; + + while (i++ < n) { + if (*s1++ != *s2++) { + break; + } + } + return(i-1); +} + +/* bskip(s1, n, b) : finds the first occurrence of any byte != 'b' in the 'n' + * bytes beginning at 's1'. + */ + +int +bskip(s1, n, b) +register char *s1; +register int n; +register int b; +{ + register int i = 0; + + while (i++ < n) { + if (*s1++ != b) { + break; + } + } + return(i-1); +} + +/* + * memNSchr(const void *s, int c, size_t n, int and) + * + * Like memchr, but the comparison is '((*s)&and) == c', + * and we increment our way through s by "stride" ('s += stride'). + * + * We optimize for the most used strides of +1 and -1. + */ + +unsigned char * +memNSchr(s, c, n, and, stride) +char *s; +int c; +unsigned int n; +int and; +int stride; +{ + register unsigned char _c, *_s, _and; + + _and = and; + _c = (c&_and); + _s = (unsigned char *)s; + switch (stride) { + case 1: + while (n--) { + if (((*_s)&_and) == _c) { + return _s; + } + _s++; + } + break; + case -1: + while (n--) { + if (((*_s)&_and) == _c) { + return _s; + } + _s--; + } + break; + default: + while (n--) { + if (((*_s)&_and) == _c) { + return _s; + } + _s += stride; + } + } + return 0; +} diff --git a/usr.bin/tn3270/general/general.h b/usr.bin/tn3270/general/general.h new file mode 100644 index 0000000..8fee245 --- /dev/null +++ b/usr.bin/tn3270/general/general.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)general.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Some general definitions. + */ + +#define numberof(x) (sizeof x/sizeof x[0]) +#define highestof(x) (numberof(x)-1) + +#if defined(unix) +#define ClearElement(x) bzero((char *)&x, sizeof x) +#define ClearArray(x) bzero((char *)x, sizeof x) +#else /* defined(unix) */ +#define ClearElement(x) memset((char *)&x, 0, sizeof x) +#define ClearArray(x) memset((char *)x, 0, sizeof x) +#endif /* defined(unix) */ + +#if defined(unix) /* Define BSD equivalent mem* functions */ +#define memcpy(dest,src,n) bcopy(src,dest,n) +#define memmove(dest,src,n) bcopy(src,dest,n) +#define memset(s,c,n) if (c == 0) { \ + bzero(s,n); \ + } else { \ + register char *src = s; \ + register int count = n; \ + \ + while (count--) { \ + *src++ = c; \ + } \ + } +#define memcmp(s1,s2,n) bcmp(s1,s2,n) +#endif /* defined(unix) */ diff --git a/usr.bin/tn3270/general/globals.c b/usr.bin/tn3270/general/globals.c new file mode 100644 index 0000000..11e565f --- /dev/null +++ b/usr.bin/tn3270/general/globals.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)globals.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Do the defining instances for the globals of tn3270. + */ + +#include "../ctlr/hostctlr.h" +#include "../ctlr/oia.h" +#include "../ctlr/options.h" +#include "../ctlr/screen.h" + + +#define DEFINING_INSTANCES + +#include "globals.h" + +#include "../general/general.h" + +/* + * init_system() + * + * Initialize the global values in case of a restart. + */ + +void +init_system() +{ + OptHome = OptLeftMargin = OptAPLmode = OptNullProcessing = 0; + OptZonesMode = OptEnterNL = OptColFieldTab = OptPacing = 0; + OptAlphaInNumeric = OptHome = OptLeftMargin = OptWordWrap = 0; + + ClearArray(Host); + CursorAddress = BufferAddress = 0; + + Lowest = Highest = 0; + + UnLocked = AidByte = 0; + +} diff --git a/usr.bin/tn3270/general/globals.h b/usr.bin/tn3270/general/globals.h new file mode 100644 index 0000000..4fb365c --- /dev/null +++ b/usr.bin/tn3270/general/globals.h @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)globals.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * This file contains all the globals used by tn3270. + * + * Since various files may want to reference this file, + * and since they may only want subsets of the globals, + * we assume they have #include'd all the other .h files + * first, and we only give those globals relevant to + * the #include'd .h files. + * + */ + +#if defined(DEFINING_INSTANCES) +#define EXTERN +#else +#define EXTERN extern +#endif + + +EXTERN int + /* + * shell_active ==> + * 1. Don't do input. + * 2. Don't do output. + * 3. Don't block in select. + * 4. When nothing to do, call shell_continue() + */ + shell_active; + + +#if defined(INCLUDED_OPTIONS) +EXTERN int OptHome; /* where home should send us */ + +EXTERN int OptLeftMargin; /* where new line should send us */ + +EXTERN char OptColTabs[80]; /* local tab stops */ + +EXTERN int OptAPLmode; + +EXTERN int OptNullProcessing; /* improved null processing */ + +EXTERN int OptZonesMode; /* zones mode off */ + +EXTERN int OptEnterNL; /* regular enter/new line keys */ + +EXTERN int OptColFieldTab; /* regular column/field tab keys */ + +EXTERN int OptPacing; /* do pacing */ + +EXTERN int OptAlphaInNumeric; /* allow alpha in numeric fields */ + +EXTERN int OptHome; + +EXTERN int OptLeftMargin; + +EXTERN int OptWordWrap; +#endif + +#if defined(INCLUDED_SCREEN) +EXTERN ScreenImage + Host[MAXSCREENSIZE]; /* host view of screen */ + +EXTERN char Orders[256]; /* Non-zero for orders */ + + /* Run-time screen geometry */ +EXTERN int + MaxNumberLines, /* How many rows the 3270 COULD have */ + MaxNumberColumns, /* How many columns the 3270 COULD have */ + NumberLines, /* How many lines the 3270 screen contains */ + NumberColumns, /* How many columns the 3270 screen contains */ + ScreenSize; + +EXTERN int CursorAddress; /* where cursor is */ +EXTERN int BufferAddress; /* where writes are going */ + +EXTERN int Lowest, Highest; + +extern char CIABuffer[]; + +EXTERN int UnLocked; /* is the keyboard unlocked */ +EXTERN int AidByte; + +#endif + +#if defined(INCLUDED_STATE) +#endif + +#if defined(INCLUDED_OIA) + +EXTERN OIA OperatorInformationArea; + +EXTERN int + oia_modified, /* Has the oia been modified */ + ps_modified; /* Has the presentation space been modified */ + +#endif /* defined(INCLUDED_OIA) */ diff --git a/usr.bin/tn3270/general/vaxbsubs.s b/usr.bin/tn3270/general/vaxbsubs.s new file mode 100644 index 0000000..096f532 --- /dev/null +++ b/usr.bin/tn3270/general/vaxbsubs.s @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)vaxbsubs.s 8.1 (Berkeley) 6/6/93 + */ + +/* This is taken from bcmp.s from 4.2. + * The output of bunequal is the offset of the byte which didn't match; + * if all the bytes match, then we return n. + * + * BUGNOTE: This has no chance of working for lengths greater than 64K. + * (so, if you use this somewhere else, you may need to + * fix it...) + */ + +/* bunequal(s1, s2, n) */ + +#include "defs.h" + +ENTRY(bunequal) + movl 4(ap),r1 + movl 8(ap),r3 + movl 12(ap),r4 +1: + movzwl $65535,r0 + cmpl r4,r0 + jleq 2f + subl2 r0,r4 + cmpc3 r0,(r1),(r3) + jeql 1b + addl2 r4,r0 + /* changes... */ + subl3 r0,12(ap),r0 + /* end of changes for bunequal... */ + ret +2: + cmpc3 r4,(r1),(r3) + /* changes... */ + subl3 r0,12(ap),r0 + /* end of changes for bunequal... */ + ret + + + + +/* brand new code, using the above as base... */ +/* bskip(s1, n, b) : finds the first occurrence of any byte != 'b' in the 'n' + * bytes beginning at 's1'. + * + * BUGNOTE: This has no chance of working for lengths greater than 64K. + * (so, if you use this somewhere else, you may need to + * fix it...) + */ + +ENTRY(bskip) + movl 4(ap),r1 + movl 8(ap),r3 + movl 12(ap),r4 +1: + movzwl $65535,r0 + cmpl r3,r0 + jleq 2f + subl2 r0,r3 + skpc r4,r0,(r1) + jeql 1b + addl2 r3,r0 + subl3 r0,8(ap),r0 + ret +2: + skpc r4,r3,(r1) + subl3 r0,8(ap),r0 + ret diff --git a/usr.bin/tn3270/mset/Makefile b/usr.bin/tn3270/mset/Makefile new file mode 100644 index 0000000..0094fc8 --- /dev/null +++ b/usr.bin/tn3270/mset/Makefile @@ -0,0 +1,34 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mset +CFLAGS+=-I${.CURDIR} -I. +SRCS+= astosc.c map3270.c mset.c +MAN1= mset.0 +MAN5= map3270.0 +.PATH: ${.CURDIR}/../api ${.CURDIR}/../ascii + +CLEANFILES+= astosc.OUT astosc.out + +# This and the dependency hacks below to make 'depend' target +# work right... + +DEPSRCS+= astosc.OUT map3270.c mset.c + +astosc.o: astosc.OUT +astosc.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h +astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${.CURDIR}/../tools/mkastosc/obj/mkastosc + ${.CURDIR}/../tools/mkastosc/obj/mkastosc \ + ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h \ + < ${.CURDIR}/../ctlr/${KBD} > ${.TARGET} + rm -f astosc.out; ln -s astosc.OUT astosc.out + +# astosc.out +${.CURDIR}/../tools/mkastosc/obj/mkastosc: + cd ${.CURDIR}/../tools/mkastosc; make + +depend: .depend +.depend:${DEPSRCS} + mkdep ${MKDEP} ${CFLAGS:M-[ID]*} ${.ALLSRC:M*.c} + +.include <../../Makefile.inc> +.include diff --git a/usr.bin/tn3270/mset/map3270.5 b/usr.bin/tn3270/mset/map3270.5 new file mode 100644 index 0000000..3904f3a --- /dev/null +++ b/usr.bin/tn3270/mset/map3270.5 @@ -0,0 +1,341 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)map3270.5 8.3 (Berkeley) 4/19/94 +.\" +.TH MAP3270 5 "April 19, 1994" +.UC 6 +.SH NAME +map3270 \- database for mapping ascii keystrokes into IBM 3270 keys +.SH SYNOPSIS +.B map3270 +.SH DESCRIPTION +When emulating IBM-style 3270 terminals under \s-1UNIX\s0 (see \fItn3270\fR(1)), +a mapping must be performed between sequences of keys hit on +a user's (ascii) keyboard, and the keys that are +available on a 3270. For example, a 3270 has a key labeled +.B EEOF +which erases the contents of the current field from the +location of the cursor to the end. +In order to accomplish this function, +the terminal user and a program emulating a 3270 must +agree on what keys will be typed +to invoke the +.B EEOF +function. +.PP +The requirements for these sequences are: +.nf +.ta 4n 9n +.sp + 1) that the first character of the sequence be outside of the + standard ascii printable characters; +.sp + 2) that no sequence \fIbe\fR an initial part of another (although + sequences may \fIshare\fR initial parts). +.sp +.fi +.SH FORMAT +The file consists of entries for various keyboards. The first part +of an entry lists the names of the keyboards which use that entry. +These names will often be the same as in +.I /etc/termcap +(see +.IR termcap (5)); +however, note that often the terminals from various termcap entries will all +use the same +.I map3270 +entry; for example, both 925 and 925vb (for +925 with visual bells) would probably use the same +.I map3270 +entry. +Additionally, there are occasions when the terminal type defines +a window manager, and it will then be necessary to specify a +keyboard name (via the +.B KEYBD +environment variable) as the name of the entry. +After the names, separated by vertical bars (`|'), comes a left +brace (`{'); the definitions; and, finally, a right brace +(`}'). +.PP +Each definition consists of a reserved keyword (see list below) which +identifies the 3270 function (extended as defined below), followed +by an equal sign (`='), followed by the various ways to generate +this particular function, followed by a semi-colon (`;'). +Each way is a sequence of strings of +.I printable +ascii characters enclosed inside single quotes (`\(aa'); +various ways (alternatives) are separated by vertical bars (`|'). +.PP +Inside the single quotes, a few characters are special. +A caret +(`^') specifies that the next character is +the ``control'' character of whatever the character is. +So, `^a' +represents control-a, ie: hexadecimal 1 +(note that `^A' would generate the same code). +To generate +.B rubout +(DEL), +one enters `^?'. +To represent a control character inside a file +requires using the caret to represent a control sequence; +simply typing control-A will not work. +Note: the ctrl-caret sequence +(to generate a hexadecimal 1E) +is represented as `^^' (not `^\e^'). +.PP +In addition to the caret, a letter may be preceded by a backslash (`\e'). +Since this has little effect for most characters, +its use is usually not recommended. +For the case of a single quote (`\(aa'), the backslash +prevents that single quote from terminating the string. +For the case of a caret (`^'), the backslash prevents +the caret from having its special meaning. +To have the backslash be part of the string, it is necessary to +place two backslashes ('\e\e') in the file. +.PP +In addition, the following characters are special: +.sp +.nf +.in +0.5i +`\eE' means an escape character; +`\en' means newline; +`\et' means tab; +`\er' means carriage return. +.in -0.5i +.fi +.sp +It is not necessary for each character in a string +to be enclosed within single quotes. +`\eE\eE\eE' means three escape characters. +.PP +Comments, which may appear anywhere on a line, +begin with a hash mark (`#'), and terminate +at the end of that line. +However, comments cannot begin inside a quoted string; +a hash mark inside a quoted string has no special meaning. +.PP +.SH 3270 KEYS SUPPORTED +The following is the list of 3270 key names that are supported in this file. +Note that some of the keys don't really exist on a 3270. +In particular, the developers of this file have relied +extensively on the work at the Yale University Computer Center with +their 3270 emulator which runs in an IBM Series/1 front end. +The following list corresponds closely to the functions +that the developers of the Yale code offer in their product. +.sp +.B In the following list, the +.B starred ("*") +.B functions are not supported by +.IR tn3270 (1). +An unsupported function will cause +.IR tn3270(1) +to send a (possibly visual) bell sequence to the user's terminal. +.sp +.nf + 3270 Key Name Functional description + + (*)LPRT local print + DP dup character + FM field mark character + CURSEL cursor select + CENTSIGN EBCDIC cent sign + RESHOW redisplay the screen + EINP erase input + EEOF erase end of field + DELETE delete character + INSRT toggle insert mode + TAB field tab + BTAB field back tab + COLTAB column tab + COLBAK column back tab + INDENT indent one tab stop + UNDENT undent one tab stop + NL new line + HOME home the cursor + UP up cursor + DOWN down cursor + RIGHT right cursor + LEFT left cursor + SETTAB set a column tab + DELTAB delete a columntab + SETMRG set left margin + SETHOM set home position + CLRTAB clear all column tabs + (*)APLON apl on + (*)APLOFF apl off + (*)APLEND treat input as ascii + (*)PCON xon/xoff on + (*)PCOFF xon/xoff off + DISC disconnect (suspend) + (*)INIT new terminal type + (*)ALTK alternate keyboard dvorak + FLINP flush input + ERASE erase last character + WERASE erase last word + FERASE erase field + SYNCH we are in synch with the user + RESET reset key-unlock keyboard + MASTER_RESET reset, unlock and redisplay + (*)XOFF please hold output + (*)XON please give me output + ESCAPE enter telnet command mode + WORDTAB tab to beginning of next word + WORDBACKTAB tab to beginning of current/last word + WORDEND tab to end of current/next word + FIELDEND tab to last non-blank of current/next + unprotected (writable) field. + + PA1 program attention 1 + PA2 program attention 2 + PA3 program attention 3 + + CLEAR local clear of the 3270 screen + TREQ test request + ENTER enter key + + PFK1 program function key 1 + PFK2 program function key 2 + etc. etc. + PFK36 program function key 36 +.SH A SAMPLE ENTRY +The following entry is used by +tn3270(1) when unable to locate a reasonable version in the +user's environment and in /etc/map3270: +.sp +.nf + name { # actual name comes from TERM variable + clear = '^z'; + flinp = '^x'; + enter = '^m'; + delete = '^d' | '^?'; # note that '^?' is delete (rubout) + synch = '^r'; + reshow = '^v'; + eeof = '^e'; + tab = '^i'; + btab = '^b'; + nl = '^n'; + left = '^h'; + right = '^l'; + up = '^k'; + down = '^j'; + einp = '^w'; + reset = '^t'; + xoff = '^s'; + xon = '^q'; + escape = '^c'; + ferase = '^u'; + insrt = '\E '; + # program attention keys + pa1 = '^p1'; pa2 = '^p2'; pa3 = '^p3'; + # program function keys + pfk1 = '\eE1'; pfk2 = '\eE2'; pfk3 = '\eE3'; pfk4 = '\eE4'; + pfk5 = '\eE5'; pfk6 = '\eE6'; pfk7 = '\eE7'; pfk8 = '\eE8'; + pfk9 = '\eE9'; pfk10 = '\eE0'; pfk11 = '\eE-'; pfk12 = '\eE='; + pfk13 = '\eE!'; pfk14 = '\eE@'; pfk15 = '\eE#'; pfk16 = '\eE$'; + pfk17 = '\eE%'; pfk18 = '\eE'; pfk19 = '\eE&'; pfk20 = '\eE*'; + pfk21 = '\eE('; pfk22 = '\eE)'; pfk23 = '\eE_'; pfk24 = '\eE+'; + } +.fi +.SH "IBM 3270 KEY DEFINITONS FOR AN ABOVE DEFINITION" +The charts below show the proper keys to emulate +each 3270 function when using the default key mapping supplied +with +.IR tn3270 (1) +and +.IR mset (1). +.sp +.nf + Command Keys IBM 3270 Key Default Key(s) + Enter RETURN + Clear control-z + Cursor Movement Keys + New Line control-n or + Home + Tab control-i + Back Tab control-b + Cursor Left control-h + Cursor Right control-l + Cursor Up control-k + Cursor Down control-j or + LINE FEED + Edit Control Keys + Delete Char control-d or + RUB + Erase EOF control-e + Erase Input control-w + Insert Mode ESC Space + End Insert ESC Space + Program Function Keys + PF1 ESC 1 + PF2 ESC 2 + ... ... + PF10 ESC 0 + PF11 ESC - + PF12 ESC = + PF13 ESC ! + PF14 ESC @ + ... ... + PF24 ESC + + Program Attention Keys + PA1 control-p 1 + PA2 control-p 2 + PA3 control-p 3 + Local Control Keys + Reset After Error control-r + Purge Input Buffer control-x + Keyboard Unlock control-t + Redisplay Screen control-v + Other Keys + Erase current field control-u +.fi +.SH FILES +/etc/map3270 +.SH SEE ALSO +tn3270(1), mset(1), \fIYale ASCII Terminal Communication +System II Program Description/Operator's Manual\fR +(IBM SB30-1911) +.SH AUTHOR +Greg Minshall +.SH BUGS +.I Tn3270 +doesn't yet understand how to process all the functions +available in +.I map3270; +when such a function is requested +.I tn3270 +will beep at you. +.PP +The definition of "word" (for "word erase", "word tab") should be a run-time +option. Currently it is defined as the kernel tty driver defines it (strings +of non-whitespace); more than one person would rather use the "vi" definition +(strings of specials, strings of alphanumeric). diff --git a/usr.bin/tn3270/mset/mset.1 b/usr.bin/tn3270/mset/mset.1 new file mode 100644 index 0000000..a806eaa --- /dev/null +++ b/usr.bin/tn3270/mset/mset.1 @@ -0,0 +1,188 @@ +.\" Copyright (c) 1986, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mset.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt MSET 1 +.Os BSD 4.3 +.Sh NAME +.Nm mset +.Nd retrieve +.Tn ASCII +to +.Tn IBM +3270 keyboard map +.Sh SYNOPSIS +.Nm mset +.Op Fl picky +.Op Fl shell +.Op Ar keyboardname +.Sh DESCRIPTION +.Nm Mset +retrieves mapping information +for the +.Tn ASCII +keyboard to +.Tn IBM +3270 terminal +special functions. +Normally, these mappings are found +in +.Pa /usr/share/misc/map3270 +(see +.Xr map3270 5 ) . +This information is used by the +.Xr tn3270 +command (see +.Xr tn3270 1 ) . +.Pp +The default +.Nm mset +output can be used to store the mapping information in the process environment +in order to avoid scanning +.Nm map3270 +each time +.Nm tn3270 +is invoked. +To do this, place the following command in your +.Pa .login +file: +.Bd -literal -offset indent +set noglob; setenv MAP3270 "\(gamset\(ga"; unset noglob +.Ed +.Pp +If the +.Ar keyboardname +argument is not supplied, +.Nm mset +attempts to determine the name of the keyboard the user is using, +by checking the +.Ev KEYBD +environment variable. +If the +.Ev KEYBD +environment variable is not set, then +.Nm mset +uses the user's terminal type from the environment variable +.Ev TERM +as the keyboard name. +Normally, +.Nm mset +then uses the file +.Xr map3270 5 +to find the keyboard mapping for that terminal. +However, if the environment variable +.Ev MAP3270 +exists and contains the entry for the specified keyboard, then that +definition is used. +If the value of +.Ev MAP3270 +begins with a slash (`/') then it is assumed to be the full pathname +of an alternate mapping file and that file is searched first. +In any case, if the mapping for the keyboard is not found in +the environment, nor in an alternate map file, nor in the standard map file, +then the same search is performed for an entry for a keyboard with the name +.Ar unknown . +If that search also fails, +then a default mapping +is used. +.Pp +The arguments to +.Nm mset +are: +.Pp +.Bl -tag -width Fl +.It Fl picky +When processing the various +.Pa map3270 +entries (for the user's keyboard, +and all those encountered before the one for the user's keyboard), +.Nm mset +normally will not complain about entries for unknown functions (like +.Dq PFX1 ; +the +.Fl picky +argument causes +.Nm mset +to issue warning messages about these unknown entries. +.It Fl shell +If the +.Pa map3270 +entry is longer than the shell's 1024 environmental variable +length limit, the default +.Nm mset +output cannot be used to store the mapping information in the process +environment to avoid scanning +.Pa map3270 +each time +.Nm tn3270 +is invoked. +The +.Fl shell +argument causes +.Nm mset +to generate shell commands to set the environmental variables +.Ev MAP3270 , +.Ev MAP3270A , +and so on, breaking up the entry to fit within the shell environmental +variable length limit. +To set these variables, place the following command in your +.Pa .login +file: +.Bd -literal -offset indent +mset -shell > tmp ; source tmp ; /bin/rm tmp +.Ed +.It Ar keyboardname +When searching for the +.Pa map3270 +entry that matches the user's keyboard, +.Nm mset +will use +.Ar keyboardname +instead of determining the keyboard name from the +.Ev KEYBD +or +.Ev TERM +environmental variables. +.Sh FILES +.Bl -tag -width /usr/share/misc/map3270 -compact +.It Pa /usr/share/misc/map3270 +keyboard mapping for known keyboards +.El +.Sh SEE ALSO +.Xr tn3270 1 , +.Xr map3270 5 +.Sh HISTORY +The +.Nm mset +command appeared in +.Bx 4.3 . diff --git a/usr.bin/tn3270/sys_curses/system.c b/usr.bin/tn3270/sys_curses/system.c new file mode 100644 index 0000000..14a99bd --- /dev/null +++ b/usr.bin/tn3270/sys_curses/system.c @@ -0,0 +1,753 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)system.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#if defined(pyr) +#define fd_set fdset_t +#endif /* defined(pyr) */ + +/* + * Wouldn't it be nice if these REALLY were in ? Or, + * equivalently, if REALLY existed? + */ +#define IREAD 00400 +#define IWRITE 00200 + +#include +#include +#include +#include +#include + +#include +extern int errno; + +#include +#include +#include +#include +#include + +#include "../general/general.h" +#include "../ctlr/api.h" +#include "../api/api_exch.h" + +#include "../general/globals.h" + +#ifndef FD_SETSIZE +/* + * The following is defined just in case someone should want to run + * this telnet on a 4.2 system. + * + */ + +#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) +#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) +#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) +#define FD_ZERO(p) ((p)->fds_bits[0] = 0) + +#endif + +static int shell_pid = 0; +static char key[50]; /* Actual key */ +static char *keyname; /* Name of file with key in it */ + +static char *ourENVlist[200]; /* Lots of room */ + +static int + sock = -1, /* Connected socket */ + serversock; /* Server (listening) socket */ + +static enum { DEAD, UNCONNECTED, CONNECTED } state; + +static long + storage_location; /* Address we have */ +static short + storage_length = 0; /* Length we have */ +static int + storage_must_send = 0, /* Storage belongs on other side of wire */ + storage_accessed = 0; /* The storage is accessed (so leave alone)! */ + +static long storage[1000]; + +static union REGS inputRegs; +static struct SREGS inputSregs; + +extern int apitrace; + +static void +kill_connection() +{ + state = UNCONNECTED; + if (sock != -1) { + (void) close(sock); + sock = -1; + } +} + + +static int +nextstore() +{ + struct storage_descriptor sd; + + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + storage_length = 0; + return -1; + } + storage_length = sd.length; + storage_location = sd.location; + if (storage_length > sizeof storage) { + fprintf(stderr, "API client tried to send too much storage (%d).\n", + storage_length); + storage_length = 0; + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) + == -1) { + storage_length = 0; + return -1; + } + return 0; +} + + +static int +doreject(message) +char *message; +{ + struct storage_descriptor sd; + int length = strlen(message); + + if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) { + return -1; + } + sd.length = length; + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { + return -1; + } + return 0; +} + + +/* + * doassociate() + * + * Negotiate with the other side and try to do something. + * + * Returns: + * + * -1: Error in processing + * 0: Invalid password entered + * 1: Association OK + */ + +static int +doassociate() +{ + struct passwd *pwent; + char + promptbuf[100], + buffer[200]; + struct storage_descriptor sd; + extern char *crypt(); + + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + return -1; + } + sd.length = sd.length; + if (sd.length > sizeof buffer) { + doreject("(internal error) Authentication key too long"); + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { + return -1; + } + buffer[sd.length] = 0; + + if (strcmp(buffer, key) != 0) { +#if (!defined(sun)) || defined(BSD) && (BSD >= 43) + extern uid_t geteuid(); +#endif /* (!defined(sun)) || defined(BSD) && (BSD >= 43) */ + + if ((pwent = getpwuid((int)geteuid())) == 0) { + return -1; + } + sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); + if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) { + return -1; + } + sd.length = strlen(promptbuf); + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) + == -1) { + return -1; + } + sd.length = strlen(pwent->pw_name); + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, + strlen(pwent->pw_name), pwent->pw_name) == -1) { + return -1; + } + if (api_exch_incommand(EXCH_CMD_AUTH) == -1) { + return -1; + } + if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) + == -1) { + return -1; + } + sd.length = sd.length; + if (sd.length > sizeof buffer) { + doreject("Password entered was too long"); + return -1; + } + if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { + return -1; + } + buffer[sd.length] = 0; + + /* Is this the correct password? */ + if (strlen(pwent->pw_name)) { + char *ptr; + int i; + + ptr = pwent->pw_name; + i = 0; + while (i < sd.length) { + buffer[i++] ^= *ptr++; + if (*ptr == 0) { + ptr = pwent->pw_name; + } + } + } + if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) { + doreject("Invalid password"); + sleep(10); /* Don't let us do too many of these */ + return 0; + } + } + if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) { + return -1; + } else { + return 1; + } +} + + +void +freestorage() +{ + struct storage_descriptor sd; + + if (storage_accessed) { + fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); + fprintf(stderr, "(Encountered in file %s at line %d.)\n", + __FILE__, __LINE__); + quit(); + } + if (storage_must_send == 0) { + return; + } + storage_must_send = 0; + if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) { + kill_connection(); + return; + } + sd.length = storage_length; + sd.location = storage_location; + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { + kill_connection(); + return; + } + if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) + == -1) { + kill_connection(); + return; + } +} + + +static int +getstorage(address, length, copyin) +long + address; +int + length, + copyin; +{ + struct storage_descriptor sd; + + freestorage(); + if (storage_accessed) { + fprintf(stderr, + "Internal error - attempt to get while storage accessed.\n"); + fprintf(stderr, "(Encountered in file %s at line %d.)\n", + __FILE__, __LINE__); + quit(); + } + storage_must_send = 0; + if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) { + kill_connection(); + return -1; + } + storage_location = address; + storage_length = length; + if (copyin) { + sd.location = (long)storage_location; + sd.length = storage_length; + if (api_exch_outtype(EXCH_TYPE_STORE_DESC, + sizeof sd, (char *)&sd) == -1) { + kill_connection(); + return -1; + } + if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) { + fprintf(stderr, "Bad data from other side.\n"); + fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__); + return -1; + } + if (nextstore() == -1) { + kill_connection(); + return -1; + } + } + return 0; +} + +/*ARGSUSED*/ +void +movetous(local, es, di, length) +char + *local; +unsigned int + es, + di; +int + length; +{ + long where = SEG_OFF_BACK(es, di); + + if (length > sizeof storage) { + fprintf(stderr, "Internal API error - movetous() length too long.\n"); + fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); + quit(); + } else if (length == 0) { + return; + } + getstorage(where, length, 1); + memcpy(local, (char *)(storage+((where-storage_location))), length); + if (apitrace) { + Dump('(', local, length); + } +} + +/*ARGSUSED*/ +void +movetothem(es, di, local, length) +unsigned int + es, + di; +char + *local; +int + length; +{ + long where = SEG_OFF_BACK(es, di); + + if (length > sizeof storage) { + fprintf(stderr, "Internal API error - movetothem() length too long.\n"); + fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); + quit(); + } else if (length == 0) { + return; + } + freestorage(); + memcpy((char *)storage, local, length); + if (apitrace) { + Dump(')', local, length); + } + storage_length = length; + storage_location = where; + storage_must_send = 1; +} + + +char * +access_api(location, length, copyin) +char * + location; +int + length, + copyin; /* Do we need to copy in initially? */ +{ + if (storage_accessed) { + fprintf(stderr, "Internal error - storage accessed twice\n"); + fprintf(stderr, "(Encountered in file %s, line %d.)\n", + __FILE__, __LINE__); + quit(); + } else if (length != 0) { + freestorage(); + getstorage((long)location, length, copyin); + storage_accessed = 1; + } + return (char *) storage; +} + +/*ARGSUSED*/ +void +unaccess_api(location, local, length, copyout) +char *location; +char *local; +int length; +int copyout; +{ + if (storage_accessed == 0) { + fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); + fprintf(stderr, "(Encountered in file %s, line %d.)\n", + __FILE__, __LINE__); + quit(); + } + storage_accessed = 0; + storage_must_send = copyout; /* if needs to go back */ +} + +/* + * Accept a connection from an API client, aborting if the child dies. + */ + +static int +doconnect() +{ + fd_set fdset; + int i; + + sock = -1; + FD_ZERO(&fdset); + while (shell_active && (sock == -1)) { + FD_SET(serversock, &fdset); + if ((i = select(serversock+1, &fdset, + (fd_set *)0, (fd_set *)0, (struct timeval *)0)) < 0) { + if (errno = EINTR) { + continue; + } else { + perror("in select waiting for API connection"); + return -1; + } + } else { + i = accept(serversock, (struct sockaddr *)0, (int *)0); + if (i == -1) { + perror("accepting API connection"); + return -1; + } + sock = i; + } + } + /* If the process has already exited, we may need to close */ + if ((shell_active == 0) && (sock != -1)) { + extern void setcommandmode(); + + (void) close(sock); + sock = -1; + setcommandmode(); /* In case child_died sneaked in */ + } + return 0; +} + +/* + * shell_continue() actually runs the command, and looks for API + * requests coming back in. + * + * We are called from the main loop in telnet.c. + */ + +int +shell_continue() +{ + int i; + + switch (state) { + case DEAD: + pause(); /* Nothing to do */ + break; + case UNCONNECTED: + if (doconnect() == -1) { + kill_connection(); + return -1; + } + /* At this point, it is possible that we've gone away */ + if (shell_active == 0) { + kill_connection(); + return -1; + } + if (api_exch_init(sock, "server") == -1) { + return -1; + } + while (state == UNCONNECTED) { + if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) { + kill_connection(); + return -1; + } else { + switch (doassociate()) { + case -1: + kill_connection(); + return -1; + case 0: + break; + case 1: + state = CONNECTED; + } + } + } + break; + case CONNECTED: + switch (i = api_exch_nextcommand()) { + case EXCH_CMD_REQUEST: + if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs, + (char *)&inputRegs) == -1) { + kill_connection(); + } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs, + (char *)&inputSregs) == -1) { + kill_connection(); + } else if (nextstore() == -1) { + kill_connection(); + } else { + handle_api(&inputRegs, &inputSregs); + freestorage(); /* Send any storage back */ + if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) { + kill_connection(); + } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs, + (char *)&inputRegs) == -1) { + kill_connection(); + } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs, + (char *)&inputSregs) == -1) { + kill_connection(); + } + /* Done, and it all worked! */ + } + break; + case EXCH_CMD_DISASSOCIATE: + kill_connection(); + break; + default: + if (i != -1) { + fprintf(stderr, + "Looking for a REQUEST or DISASSOCIATE command\n"); + fprintf(stderr, "\treceived 0x%02x.\n", i); + } + kill_connection(); + break; + } + } + return shell_active; +} + + +static void +child_died(code) +{ + union wait status; + register int pid; + + while ((pid = wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { + if (pid == shell_pid) { + char inputbuffer[100]; + extern void setconnmode(); + extern void ConnectScreen(); + + shell_active = 0; + if (sock != -1) { + (void) close(sock); + sock = -1; + } + printf("[Hit return to continue]"); + fflush(stdout); + (void) gets(inputbuffer); + setconnmode(); + ConnectScreen(); /* Turn screen on (if need be) */ + (void) close(serversock); + (void) unlink(keyname); + } + } + signal(SIGCHLD, child_died); +} + + +/* + * Called from telnet.c to fork a lower command.com. We + * use the spint... routines so that we can pick up + * interrupts generated by application programs. + */ + + +int +shell(argc,argv) +int argc; +char *argv[]; +{ + int length; + struct sockaddr_in server; + char sockNAME[100]; + static char **whereAPI = 0; + int fd; + struct timeval tv; + long ikey; + extern long random(); + extern char *mktemp(); + extern char *strcpy(); + + /* First, create verification file. */ + do { + keyname = mktemp(strdup("/tmp/apiXXXXXX")); + fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE); + } while ((fd == -1) && (errno == EEXIST)); + + if (fd == -1) { + perror("open"); + return 0; + } + + /* Now, get seed for random */ + + if (gettimeofday(&tv, (struct timezone *)0) == -1) { + perror("gettimeofday"); + return 0; + } + srandom(tv.tv_usec); /* seed random number generator */ + do { + ikey = random(); + } while (ikey == 0); + sprintf(key, "%lu\n", (unsigned long) ikey); + if (write(fd, key, strlen(key)) != strlen(key)) { + perror("write"); + return 0; + } + key[strlen(key)-1] = 0; /* Get rid of newline */ + + if (close(fd) == -1) { + perror("close"); + return 0; + } + + /* Next, create the socket which will be connected to */ + serversock = socket(AF_INET, SOCK_STREAM, 0); + if (serversock < 0) { + perror("opening API socket"); + return 0; + } + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = 0; + if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) { + perror("binding API socket"); + return 0; + } + length = sizeof server; + if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) { + perror("getting API socket name"); + (void) close(serversock); + } + listen(serversock, 1); + /* Get name to advertise in address list */ + strcpy(sockNAME, "API3270="); + gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); + if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) { + fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); + strcpy(sockNAME, "localhost"); + } + sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port)); + sprintf(sockNAME+strlen(sockNAME), ":%s", keyname); + + if (whereAPI == 0) { + char **ptr, **nextenv; + extern char **environ; + + ptr = environ; + nextenv = ourENVlist; + while (*ptr) { + if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { + fprintf(stderr, "Too many environmental variables\n"); + break; + } + *nextenv++ = *ptr++; + } + whereAPI = nextenv++; + *nextenv++ = 0; + environ = ourENVlist; /* New environment */ + } + *whereAPI = sockNAME; + + child_died(); /* Start up signal handler */ + shell_active = 1; /* We are running down below */ + if (shell_pid = vfork()) { + if (shell_pid == -1) { + perror("vfork"); + (void) close(serversock); + } else { + state = UNCONNECTED; + } + } else { /* New process */ + register int i; + + for (i = 3; i < 30; i++) { + (void) close(i); + } + if (argc == 1) { /* Just get a shell */ + char *cmdname; + extern char *getenv(); + + cmdname = getenv("SHELL"); + execlp(cmdname, cmdname, 0); + perror("Exec'ing new shell...\n"); + exit(1); + } else { + execvp(argv[1], &argv[1]); + perror("Exec'ing command.\n"); + exit(1); + } + /*NOTREACHED*/ + } + return shell_active; /* Go back to main loop */ +} diff --git a/usr.bin/tn3270/sys_curses/telextrn.h b/usr.bin/tn3270/sys_curses/telextrn.h new file mode 100644 index 0000000..becf82a2 --- /dev/null +++ b/usr.bin/tn3270/sys_curses/telextrn.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)telextrn.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Definitions of external routines and variables for tn3270 + */ + +/* + * Pieces exported from the telnet susbsection. + */ + +extern int +#if defined(unix) + HaveInput, +#endif /* defined(unix) */ + tout, + tin; + +extern char *transcom; + +extern int + netflush(), + quit(), + TtyChars(), + DataToTerminal(); + +extern void + outputPurge(), + EmptyTerminal(), + StringToTerminal(), + ExitPerror(), + setcommandmode(); + +/* + * Pieces exported from other random locations. + */ + +extern char + *strsave(); diff --git a/usr.bin/tn3270/sys_curses/terminal.h b/usr.bin/tn3270/sys_curses/terminal.h new file mode 100644 index 0000000..d7041b7 --- /dev/null +++ b/usr.bin/tn3270/sys_curses/terminal.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)terminal.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_TERMINAL + +/* + * In the situation where we have a copy of the terminal screen in front + * of us, here are some macros to deal with them. + */ + +#define TermAttributes(x) (TermIsStartField(x)? GetTerminal(x)&0xff : \ + GetTerminal(WhereTermAttrByte(x))&0xff) +#define TermIsStartField(x) ((GetTerminal(x)&ATTR_MASK) == ATTR_MASK) +#define TermNewField(p,a) SetTerminal(p, (a)|ATTR_MASK) +#define TermDeleteField(p) SetTerminal(p, 0) +#define TermIsNonDisplay(x) \ + ((TermAttributes(x)&ATTR_DSPD_MASK) == ATTR_DSPD_NONDISPLAY) +#define TermIsHighlighted(x) \ + (((TermAttributes(x)&ATTR_DSPD_MASK) == ATTR_DSPD_HIGH) \ + && !TermIsStartField(x)) + +#define TerminalCharacterAttr(c,p,a) (IsNonDisplayAttr(a) ? ' ':c) +#define TerminalCharacter(c,p) TerminalCharacterAttr(c,p,FieldAttributes(p)) + + /* + * Is the screen formatted? Some algorithms change depending + * on whether there are any attribute bytes lying around. + */ +#define TerminalFormattedScreen() \ + ((WhereTermAttrByte(0) != 0) || ((GetTerminal(0)&ATTR_MASK) == ATTR_MASK)) + +#define NeedToRedisplayFields(p) ((TermIsNonDisplay(p) != IsNonDisplay(p)) || \ + (TermIsHighlighted(p) != IsHighlighted(p))) +#define NeedToRedisplayFieldsAttr(p,c) ( \ + (TermIsNonDisplay(p) != IsNonDisplayAttr(c)) || \ + (TermIsHighlighted(p) != IsHighlightedAttr(c))) + +#define NotVisuallyCompatibleAttributes(p,c,d) ( \ + (IsNonDisplayAttr(c) != IsNonDisplayAttr(d)) || \ + (IsHighlightedAttr(c) != IsHighlightedAttr(d))) + +#define NeedToRedisplayAttr(c,p,a) \ + ((c != GetTerminal(p)) || NeedToRedisplayFieldsAttr(p,a)) +#define NeedToRedisplay(c,p) NeedToRedisplayAttr(c,p,FieldAttributes(p)) + + +#define GetTerminal(i) GetGeneric(i, Terminal) +#define GetTerminalPointer(p) GetGenericPointer(p) +#define SetTerminal(i,c) SetGeneric(i,c,Terminal) diff --git a/usr.bin/tn3270/sys_curses/termout.c b/usr.bin/tn3270/sys_curses/termout.c new file mode 100644 index 0000000..5dbe311 --- /dev/null +++ b/usr.bin/tn3270/sys_curses/termout.c @@ -0,0 +1,957 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)termout.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#if defined(unix) +#include +#include +#endif +#include +#include +#if defined(ultrix) +/* Some version of this OS has a bad definition for nonl() */ +#undef nl +#undef nonl + +#define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) +#define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) +#endif /* defined(ultrix) */ + +#include "../general/general.h" + +#include "terminal.h" + +#include "../api/disp_asc.h" + +#include "../ctlr/hostctlr.h" +#include "../ctlr/externs.h" +#include "../ctlr/declare.h" +#include "../ctlr/oia.h" +#include "../ctlr/screen.h" +#include "../ctlr/scrnctlr.h" + +#include "../general/globals.h" + +#include "telextrn.h" + +#define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ + CursorAddress:UnLocked? CursorAddress: HighestScreen()) + + +static int terminalCursorAddress; /* where the cursor is on term */ +static int screenInitd; /* the screen has been initialized */ +static int screenStopped; /* the screen has been stopped */ +static int max_changes_before_poll; /* how many characters before looking */ + /* at terminal and net again */ + +static int needToRing; /* need to ring terinal bell */ +static char *bellSequence = "\07"; /* bell sequence (may be replaced by + * VB during initialization) + */ +static WINDOW *bellwin = 0; /* The window the bell message is in */ +int bellwinup = 0; /* Are we up with it or not */ + +#if defined(unix) +static char *myKS, *myKE; +#endif /* defined(unix) */ + + +static int inHighlightMode = 0; +ScreenImage Terminal[MAXSCREENSIZE]; + +/* Variables for transparent mode */ +#if defined(unix) +static int tcflag = -1; /* transparent mode command flag */ +static int savefd[2]; /* for storing fds during transcom */ +extern int tin, tout; /* file descriptors */ +#endif /* defined(unix) */ + + +/* + * init_screen() + * + * Initialize variables used by screen. + */ + +void +init_screen() +{ + bellwinup = 0; + inHighlightMode = 0; + ClearArray(Terminal); +} + + +/* OurExitString - designed to keep us from going through infinite recursion */ + +static void +OurExitString(string, value) +char *string; +int value; +{ + static int recursion = 0; + + if (!recursion) { + recursion = 1; + ExitString(string, value); + } +} + + +/* DoARefresh */ + +static void +DoARefresh() +{ + if (ERR == refresh()) { + OurExitString("ERR from refresh\n", 1); + } +} + +static void +GoAway(from, where) +char *from; /* routine that gave error */ +int where; /* cursor address */ +{ + char foo[100]; + + sprintf(foo, "ERR from %s at %d (%d, %d)\n", + from, where, ScreenLine(where), ScreenLineOffset(where)); + OurExitString(foo, 1); + /* NOTREACHED */ +} + +/* What is the screen address of the attribute byte for the terminal */ + +static int +WhereTermAttrByte(p) +register int p; +{ + register int i; + + i = p; + + do { + if (TermIsStartField(i)) { + return(i); + } + i = ScreenDec(i); + } while (i != p); + + return(LowestScreen()); /* unformatted screen... */ +} + +/* + * There are two algorithms for updating the screen. + * The first, SlowScreen() optimizes the line between the + * computer and the screen (say a 9600 baud line). To do + * this, we break out of the loop every so often to look + * at any pending input from the network (so that successive + * screens will only partially print until the final screen, + * the one the user possibly wants to see, is displayed + * in its entirety). + * + * The second algorithm tries to optimize CPU time (by + * being simpler) at the cost of the bandwidth to the + * screen. + * + * Of course, curses(3X) gets in here also. + */ + + +#if defined(NOT43) +static int +#else /* defined(NOT43) */ +static void +#endif /* defined(NOT43) */ +SlowScreen() +{ + register int is, shouldbe, isattr, shouldattr; + register int pointer; + register int fieldattr, termattr; + register int columnsleft; + +#define NORMAL 0 +#define HIGHLIGHT 1 /* Mask bits */ +#define NONDISPLAY 4 /* Mask bits */ +#define UNDETERMINED 8 /* Mask bits */ + +#define DoAttributes(x) \ + switch (x&ATTR_DSPD_MASK) { \ + case ATTR_DSPD_NONDISPLAY: \ + x = NONDISPLAY; \ + break; \ + case ATTR_DSPD_HIGH: \ + x = HIGHLIGHT; \ + break; \ + default: \ + x = 0; \ + break; \ + } + +# define SetHighlightMode(x) \ + { \ + if ((x)&HIGHLIGHT) { \ + if (!inHighlightMode) { \ + inHighlightMode = HIGHLIGHT; \ + standout(); \ + } \ + } else { \ + if (inHighlightMode) { \ + inHighlightMode = 0; \ + standend(); \ + } \ + } \ + } + +# define DoCharacterAt(c,p) { \ + if (p != HighestScreen()) { \ + c = disp_asc[c&0xff]; \ + if (terminalCursorAddress != p) { \ + if (ERR == mvaddch(ScreenLine(p), \ + ScreenLineOffset(p), c)) {\ + GoAway("mvaddch", p); \ + } \ + } else { \ + if (ERR == addch(c)) {\ + GoAway("addch", p); \ + } \ + } \ + terminalCursorAddress = ScreenInc(p); \ + } \ + } + + + /* run through screen, printing out non-null lines */ + + /* There are two separate reasons for wanting to terminate this + * loop early. One is to respond to new input (either from + * the terminal or from the network [host]). For this reason, + * we expect to see 'HaveInput' come true when new input comes in. + * + * The second reason is a bit more difficult (for me) to understand. + * Basically, we don't want to get too far ahead of the characters that + * appear on the screen. Ideally, we would type out a few characters, + * wait until they appeared on the screen, then type out a few more. + * The reason for this is that the user, on seeing some characters + * appear on the screen may then start to type something. We would + * like to look at what the user types at about the same 'time' + * (measured by characters being sent to the terminal) that the + * user types them. For this reason, what we would like to do + * is update a bit, then call curses to do a refresh, flush the + * output to the terminal, then wait until the terminal data + * has been sent. + * + * Note that curses is useful for, among other things, deciding whether + * or not to send :ce: (clear to end of line), so we should call curses + * at end of lines (beginning of next lines). + * + * The problems here are the following: If we do lots of write(2)s, + * we will be doing lots of context switches, thus lots of overhead + * (which we have already). Second, if we do a select to wait for + * the output to drain, we have to contend with the fact that NOW + * we are scheduled to run, but who knows what the scheduler will + * decide when the output has caught up. + */ + + if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ + Highest = ScreenDec(Highest); /* else, while loop will never end */ + } + if (Lowest < LowestScreen()) { + Lowest = LowestScreen(); /* could be -1 in some cases with + * unformatted screens. + */ + } + if (Highest >= (pointer = Lowest)) { + /* if there is anything to do, do it. We won't terminate + * the loop until we've gone at least to Highest. + */ + while ((pointer <= Highest) && !HaveInput) { + + /* point at the next place of disagreement */ + pointer += (bunequal(Host+pointer, Terminal+pointer, + (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); + + /* + * How many characters to change until the end of the + * current line + */ + columnsleft = NumberColumns - ScreenLineOffset(pointer); + /* + * Make sure we are where we think we are. + */ + move(ScreenLine(pointer), ScreenLineOffset(pointer)); + + /* what is the field attribute of the current position */ + if (FormattedScreen()) { + fieldattr = FieldAttributes(pointer); + DoAttributes(fieldattr); + } else { + fieldattr = NORMAL; + } + if (TerminalFormattedScreen()) { + termattr = TermAttributes(pointer); + DoAttributes(termattr); + } else { + termattr = NORMAL; + } + + SetHighlightMode(fieldattr); + /* + * The following will terminate at least when we get back + * to the original 'pointer' location (since we force + * things to be equal). + */ + for (;;) { + if (IsStartField(pointer)) { + shouldbe = DISP_BLANK; + shouldattr = 0; + fieldattr = GetHost(pointer); + DoAttributes(fieldattr); + } else { + if (fieldattr&NONDISPLAY) { + shouldbe = DISP_BLANK; + } else { + shouldbe = GetHost(pointer); + } + shouldattr = fieldattr; + } + if (TermIsStartField(pointer)) { + is = DISP_BLANK; + isattr = 0; + termattr = UNDETERMINED; /* Need to find out AFTER update */ + } else { + if (termattr&NONDISPLAY) { + is = DISP_BLANK; + } else { + is = GetTerminal(pointer); + } + isattr = termattr; + } + if ((shouldbe == is) && (shouldattr == isattr) + && (GetHost(pointer) == GetTerminal(pointer)) + && (GetHost(ScreenInc(pointer)) + == GetTerminal(ScreenInc(pointer)))) { + break; + } + + if (shouldattr^inHighlightMode) { + SetHighlightMode(shouldattr); + } + + DoCharacterAt(shouldbe, pointer); + if (IsStartField(pointer)) { + TermNewField(pointer, FieldAttributes(pointer)); + termattr = GetTerminal(pointer); + DoAttributes(termattr); + } else { + SetTerminal(pointer, GetHost(pointer)); + /* + * If this USED to be a start field location, + * recompute the terminal attributes. + */ + if (termattr == UNDETERMINED) { + termattr = WhereTermAttrByte(pointer); + if ((termattr != 0) || TermIsStartField(0)) { + termattr = GetTerminal(termattr); + DoAttributes(termattr); + } else { /* Unformatted screen */ + termattr = NORMAL; + } + } + } + pointer = ScreenInc(pointer); + if (!(--columnsleft)) { + DoARefresh(); + EmptyTerminal(); + if (HaveInput) { /* if input came in, take it */ + int c, j; + + /* + * We need to start a new terminal field + * at this location iff the terminal attributes + * of this location are not what we have had + * them as (ie: we've overwritten the terminal + * start field, a the previous field had different + * display characteristics). + */ + + isattr = TermAttributes(pointer); + DoAttributes(isattr); + if ((!TermIsStartField(pointer)) && + (isattr != termattr)) { + /* + * Since we are going to leave a new field + * at this terminal position, we + * need to make sure that we get an actual + * non-highlighted blank on the screen. + */ + if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { + SetHighlightMode(0); /* Turn off highlight */ + c = ScreenInc(pointer); + j = DISP_BLANK; + DoCharacterAt(j, c); + } + if (termattr&HIGHLIGHT) { + termattr = ATTR_DSPD_HIGH; + } else if (termattr&NONDISPLAY) { + termattr = ATTR_DSPD_NONDISPLAY; + } else { + termattr = 0; + } + TermNewField(pointer, termattr); + } + break; + } + move(ScreenLine(pointer), 0); + columnsleft = NumberColumns; + } + } /* end of for (;;) */ + } /* end of while (...) */ + } + DoARefresh(); + Lowest = pointer; + if (Lowest > Highest) { /* if we finished input... */ + Lowest = HighestScreen()+1; + Highest = LowestScreen()-1; + terminalCursorAddress = CorrectTerminalCursor(); + if (ERR == move(ScreenLine(terminalCursorAddress), + ScreenLineOffset(terminalCursorAddress))) { + GoAway("move", terminalCursorAddress); + } + DoARefresh(); + if (needToRing) { + StringToTerminal(bellSequence); + needToRing = 0; + } + } + EmptyTerminal(); /* move data along */ + return; +} + +#if defined(NOT43) +static int +#else /* defined(NOT43) */ +static void +#endif /* defined(NOT43) */ +FastScreen() +{ +#if defined(MSDOS) +#define SaveCorner 0 +#else /* defined(MSDOS) */ +#define SaveCorner 1 +#endif /* defined(MSDOS) */ + +#define DoAttribute(a) if (IsHighlightedAttr(a)) { \ + standout(); \ + } else { \ + standend(); \ + } \ + if (IsNonDisplayAttr(a)) { \ + a = 0; /* zero == don't display */ \ + } \ + if (!FormattedScreen()) { \ + a = 1; /* one ==> do display on unformatted */\ + } + ScreenImage *p, *upper; + int fieldattr; /* spends most of its time == 0 or 1 */ + +/* OK. We want to do this a quickly as possible. So, we assume we + * only need to go from Lowest to Highest. However, if we find a + * field in the middle, we do the whole screen. + * + * In particular, we separate out the two cases from the beginning. + */ + if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { + register int columnsleft; + + move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); + p = &Host[Lowest]; +#if !defined(MSDOS) + if (Highest == HighestScreen()) { + Highest = ScreenDec(Highest); + } +#endif /* !defined(MSDOS) */ + upper = &Host[Highest]; + fieldattr = FieldAttributes(Lowest); + DoAttribute(fieldattr); /* Set standout, non-display status */ + columnsleft = NumberColumns-ScreenLineOffset(p-Host); + + while (p <= upper) { + if (IsStartFieldPointer(p)) { /* New field? */ + Highest = HighestScreen(); + Lowest = LowestScreen(); + FastScreen(); /* Recurse */ + return; + } else if (fieldattr) { /* Should we display? */ + /* Display translated data */ + addch((char)disp_asc[GetTerminalPointer(p)]); + } else { + addch(' '); /* Display a blank */ + } + /* If the physical screen is larger than what we + * are using, we need to make sure that each line + * starts at the beginning of the line. Otherwise, + * we will just string all the lines together. + */ + p++; + if (--columnsleft == 0) { + int i = p-Host; + + move(ScreenLine(i), 0); + columnsleft = NumberColumns; + } + } + } else { /* Going from Lowest to Highest */ + unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; + ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; + register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; + + *tmpend = 0; /* terminate from the beginning */ + move(0,0); + p = Host; + fieldattr = FieldAttributes(LowestScreen()); + DoAttribute(fieldattr); /* Set standout, non-display status */ + + while (p <= End) { + if (IsStartFieldPointer(p)) { /* New field? */ + if (tmp != tmpbuf) { + *tmp++ = 0; /* close out */ + addstr((char *)tmpbuf); + tmp = tmpbuf; + tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1; + } + standend(); + addch(' '); + fieldattr = FieldAttributesPointer(p); /* Get attributes */ + DoAttribute(fieldattr); /* Set standout, non-display */ + } else { + if (fieldattr) { /* Should we display? */ + /* Display translated data */ + *tmp++ = disp_asc[GetTerminalPointer(p)]; + } else { + *tmp++ = ' '; + } + } + /* If the physical screen is larger than what we + * are using, we need to make sure that each line + * starts at the beginning of the line. Otherwise, + * we will just string all the lines together. + */ + p++; + if (tmp == tmpend) { + int i = p-Host; /* Be sure the "p++" happened first! */ + + *tmp++ = 0; + addstr((char *)tmpbuf); + tmp = tmpbuf; + move(ScreenLine(i), 0); + tmpend = tmpbuf + NumberColumns; + } + } + if (tmp != tmpbuf) { + *tmp++ = 0; + addstr((char *)tmpbuf); + tmp = tmpbuf; + } + } + Lowest = HighestScreen()+1; + Highest = LowestScreen()-1; + terminalCursorAddress = CorrectTerminalCursor(); + if (ERR == move(ScreenLine(terminalCursorAddress), + ScreenLineOffset(terminalCursorAddress))) { + GoAway("move", terminalCursorAddress); + } + DoARefresh(); + if (needToRing) { + StringToTerminal(bellSequence); + needToRing = 0; + } + EmptyTerminal(); /* move data along */ + return; +} + + +/* TryToSend - send data out to user's terminal */ + +#if defined(NOT43) +int +#else /* defined(NOT43) */ +void +#endif /* defined(NOT43) */ + (*TryToSend)() = FastScreen; + +/*ARGSUSED*/ +void +ScreenOIA(oia) +OIA *oia; +{ +} + + +/* InitTerminal - called to initialize the screen, etc. */ + +void +InitTerminal() +{ +#if defined(unix) + struct sgttyb ourttyb; + static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, + 2400, 4800, 9600 }; +#endif + extern void InitMapping(); + + InitMapping(); /* Go do mapping file (MAP3270) first */ + if (!screenInitd) { /* not initialized */ +#if defined(unix) + char KSEbuffer[2050]; + char *lotsofspace = KSEbuffer; + extern void abort(); + extern char *tgetstr(); +#endif /* defined(unix) */ + + if (initscr() == ERR) { /* Initialize curses to get line size */ + ExitString("InitTerminal: Error initializing curses", 1); + /*NOTREACHED*/ + } + MaxNumberLines = LINES; + MaxNumberColumns = COLS; + ClearArray(Terminal); + terminalCursorAddress = SetBufferAddress(0,0); +#if defined(unix) + signal(SIGHUP, abort); +#endif + + TryToSend = FastScreen; +#if defined(unix) + ioctl(1, TIOCGETP, (char *) &ourttyb); + if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { + max_changes_before_poll = 1920; + } else { + max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; + if (max_changes_before_poll < 40) { + max_changes_before_poll = 40; + } + TryToSend = SlowScreen; + HaveInput = 1; /* get signals going */ + } +#endif /* defined(unix) */ + setcommandmode(); + /* + * By now, initscr() (in curses) has been called (from telnet.c), + * and the screen has been initialized. + */ +#if defined(unix) + nonl(); + /* the problem is that curses catches SIGTSTP to + * be nice, but it messes us up. + */ + signal(SIGTSTP, SIG_DFL); + if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { + myKS = strsave(myKS); + StringToTerminal(myKS); + } + if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { + myKE = strsave(myKE); + } + if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { + SO = strsave(tgetstr("md", &lotsofspace)); + SE = strsave(tgetstr("me", &lotsofspace)); + } +#endif + DoARefresh(); + setconnmode(); + if (VB && *VB) { + bellSequence = VB; /* use visual bell */ + } + screenInitd = 1; + screenStopped = 0; /* Not stopped */ + } +} + + +/* StopScreen - called when we are going away... */ + +void +StopScreen(doNewLine) +int doNewLine; +{ + if (screenInitd && !screenStopped) { + move(NumberLines-1, 1); + standend(); + inHighlightMode = 0; + DoARefresh(); + setcommandmode(); + endwin(); + setconnmode(); +#if defined(unix) + if (myKE) { + StringToTerminal(myKE); + } +#endif /* defined(unix) */ + if (doNewLine) { + StringToTerminal("\r\n"); + } + EmptyTerminal(); + screenStopped = 1; /* This is stopped */ + } +} + + +/* RefreshScreen - called to cause the screen to be refreshed */ + +void +RefreshScreen() +{ + clearok(curscr, TRUE); + (*TryToSend)(); +} + + +/* ConnectScreen - called to reconnect to the screen */ + +void +ConnectScreen() +{ + if (screenInitd) { +#if defined(unix) + if (myKS) { + StringToTerminal(myKS); + } +#endif /* defined(unix) */ + RefreshScreen(); + (*TryToSend)(); + screenStopped = 0; + } +} + +/* LocalClearScreen() - clear the whole ball of wax, cheaply */ + +void +LocalClearScreen() +{ + extern void Clear3270(); + + outputPurge(); /* flush all data to terminal */ + clear(); /* clear in curses */ + ClearArray(Terminal); + Clear3270(); + Lowest = HighestScreen()+1; /* everything in sync... */ + Highest = LowestScreen()+1; +} + + +void +BellOff() +{ + if (bellwinup) { + delwin(bellwin); + bellwin = 0; + bellwinup = 0; + touchwin(stdscr); + DoARefresh(); + } +} + + +void +RingBell(s) +char *s; +{ + needToRing = 1; + if (s) { + int len = strlen(s); + + if (len > COLS-2) { + len = COLS-2; + } + if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { + OurExitString("Error from newwin in RingBell", 1); + } + werase(bellwin); + wstandout(bellwin); + box(bellwin, '|', '-'); + if (wmove(bellwin, 1, 1) == ERR) { + OurExitString("Error from wmove in RingBell", 1); + } + while (len--) { + if (waddch(bellwin, *s++) == ERR) { + OurExitString("Error from waddch in RingBell", 1); + } + } + wstandend(bellwin); + if (wrefresh(bellwin) == ERR) { + OurExitString("Error from wrefresh in RingBell", 1); + } + bellwinup = 1; + } +} + + +/* returns a 1 if no more output available (so, go ahead and block), + or a 0 if there is more output available (so, just poll the other + sources/destinations, don't block). + */ + +int +DoTerminalOutput() +{ + /* called just before a select to conserve IO to terminal */ + if (!(screenInitd||screenStopped)) { + return 1; /* No output if not initialized */ + } + if ((Lowest <= Highest) || needToRing || + (terminalCursorAddress != CorrectTerminalCursor())) { + (*TryToSend)(); + } + if (Lowest > Highest) { + return 1; /* no more output now */ + } else { + return 0; /* more output for future */ + } +} + +/* + * The following are defined to handle transparent data. + */ + +void +TransStop() +{ +#if defined(unix) + if (tcflag == 0) { + tcflag = -1; + (void) signal(SIGCHLD, SIG_DFL); + } else if (tcflag > 0) { + setcommandmode(); + (void) close(tin); + (void) close(tout); + tin = savefd[0]; + tout = savefd[1]; + setconnmode(); + tcflag = -1; + (void) signal(SIGCHLD, SIG_DFL); + } +#endif /* defined(unix) */ + RefreshScreen(); +} + +void +TransOut(buffer, count, kind, control) +unsigned char *buffer; +int count; +int kind; /* 0 or 5 */ +int control; /* To see if we are done */ +{ +#if defined(unix) + extern char *transcom; + int inpipefd[2], outpipefd[2]; + static void aborttc(); +#endif /* defined(unix) */ + + while (DoTerminalOutput() == 0) { +#if defined(unix) + HaveInput = 0; +#endif /* defined(unix) */ + } +#if defined(unix) + if (transcom && tcflag == -1) { + while (1) { /* go thru once */ + if (pipe(outpipefd) < 0) { + break; + } + if (pipe(inpipefd) < 0) { + break; + } + if ((tcflag = fork()) == 0) { + (void) close(outpipefd[1]); + (void) close(0); + if (dup(outpipefd[0]) < 0) { + exit(1); + } + (void) close(outpipefd[0]); + (void) close(inpipefd[0]); + (void) close(1); + if (dup(inpipefd[1]) < 0) { + exit(1); + } + (void) close(inpipefd[1]); + if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { + exit(1); + } + } + (void) close(inpipefd[1]); + (void) close(outpipefd[0]); + savefd[0] = tin; + savefd[1] = tout; + setcommandmode(); + tin = inpipefd[0]; + tout = outpipefd[1]; + (void) signal(SIGCHLD, aborttc); + setconnmode(); + tcflag = 1; + break; + } + if (tcflag < 1) { + tcflag = 0; + } + } +#endif /* defined(unix) */ + (void) DataToTerminal((char *)buffer, count); + if (control && (kind == 0)) { /* Send in AID byte */ + SendToIBM(); + } else { + extern void TransInput(); + + TransInput(1, kind); /* Go get some data */ + } +} + + +#if defined(unix) +static void +aborttc(signo) + int signo; +{ + setcommandmode(); + (void) close(tin); + (void) close(tout); + tin = savefd[0]; + tout = savefd[1]; + setconnmode(); + tcflag = 0; +} +#endif /* defined(unix) */ diff --git a/usr.bin/tn3270/telnet/Makefile b/usr.bin/tn3270/telnet/Makefile new file mode 100644 index 0000000..b4095e2 --- /dev/null +++ b/usr.bin/tn3270/telnet/Makefile @@ -0,0 +1,87 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +# The following is the telnet makefile for tn3270, using the shared telnet +# sources. + +# +# TERMCAP Define this if your system is termcap based, +# otherwise a terminfo based system is assumed. +# +# SRCRT Includes code to allow you to specify source routes. +# Format is: +# [!]@hop1@hop2...[@|:]dst +# Leading ! means strict source route. +# +# NOSTRNCASECMP Define this if you do not have strncasecmp() in +# your C libarary. +# +# USE_TERMIO Define this if you have System V termio structures. +# What is here is how things are on Cray computers. +# +# KLUDGELINEMODE Define this to get the kludged up version of linemode +# that was in 4.3BSD. This is a good thing to have +# around for talking to older systems. +# + +DEFINES= -DTERMCAP -DSRCRT -DKLUDGELINEMODE -DUSE_TERMIO + + +VPATH = ${.CURDIR}/../../telnet +XINCLUDES= -I${.CURDIR}/../../telnet -I${.CURDIR} +INCLUDES= +XDEFINES = -DTN3270 +OPTIMIZE= -O +CFLAGS = ${OPTIMIZE} ${INCLUDES} ${DEFINES} +XCFLAGS= ${XINCLUDES} ${XDEFINES} +LD = ld +LDFLAGS = -r +PRINT = print +ACTION = sccs tell +LIBC= /usr/lib/libc.a +ALLH= defines.h externs.h fdset.h general.h ring.h types.h +SRCS= commands.c main.c network.c ring.c \ + sys_bsd.c telnet.c terminal.c \ + tn3270.c utilities.c +ALLHC= ${ALLH} ${SRCS} +ALLPRINT = ${ALLHC} +ALLSOURCE= ${ALLHC} Makefile Makefile_ultrix +OBJS= commands.o main.o network.o ring.o sys_bsd.o \ + telnet.o terminal.o tn3270.o utilities.o + +.c.o: + ${CC} -c ${CFLAGS} ${XCFLAGS} $< + +telprog.o: ${OBJS} ${LIBC} + ${LD} ${LDFLAGS} -o $@ ${OBJS} + +clean: FRC + rm -f telprog.o ${OBJS} core telnet + +depend: FRC ${SRCS} + mkdep ${CFLAGS} ${SRCS} + +lint: FRC ${SRCS} + lint ${CFLAGS} ${SRCS} + +tags: FRC ${ALLHC} + ctags ${ALLHC} + +print: FRC ${ALLPRINT} + ${PRINT} ${ALLPRINT} + +action: FRC + ${ACTION} + +clist: FRC ${SRCS} + @for i in ${SRCS} ; \ + do (echo ${DIRPATH}$$i); done + +hclist: FRC ${ALLHC} + @for i in ${ALLHC} ; \ + do (echo ${DIRPATH}$$i); done + +sourcelist: FRC ${ALLSOURCE} + @for i in ${ALLSOURCE} ../../telnet/Makefile ; \ + do (echo ${DIRPATH}$$i); done + +FRC: diff --git a/usr.bin/tn3270/tn3270/Makefile b/usr.bin/tn3270/tn3270/Makefile new file mode 100644 index 0000000..a9f1641 --- /dev/null +++ b/usr.bin/tn3270/tn3270/Makefile @@ -0,0 +1,80 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tn3270 +CFLAGS+=-I${.CURDIR} -I. +LDADD+= -lcurses -ltermcap -ltelnet +DPADD+= ${LIBCURSES} /usr/lib/libtermcap.a /usr/lib/libtelnet.a +CLEANFILES+= asc_disp.OUT asc_disp.out disp_asc.OUT disp_asc.out TMPfunc.out +.PATH: ${.CURDIR}/../api ${.CURDIR}/../ascii ${.CURDIR}/../ctlr +.PATH: ${.CURDIR}/../general ${.CURDIR}/../sys_curses ${.CURDIR}/../../telnet + +MAN1= tn3270.0 + +SRCS+= apilib.c api_bsd.c api_exch.c asc_ebc.c astosc.c dctype.c +SRCS+= disp_asc.c ebc_disp.c +SRCS+= map3270.c termin.c +SRCS+= api.c function.c inbound.c oia.c options.c outbound.c +SRCS+= genbsubs.c globals.c system.c termout.c +SRCS+= commands.c main.c network.c ring.c sys_bsd.c telnet.c terminal.c +SRCS+= tn3270.c utilities.c + +# This and the dependency hacks below to make 'depend' target +# work right... + +DEPSRCS+= astosc.OUT asc_disp.OUT disp_asc.OUT kbd.OUT +DEPSRCS+= apilib.c api_bsd.c api_exch.c asc_ebc.c dctype.c +DEPSRCS+= ebc_disp.c +DEPSRCS+= map3270.c termin.c +DEPSRCS+= api.c function.c inbound.c oia.c options.c outbound.c +DEPSRCS+= genbsubs.c globals.c system.c termout.c +DEPSRCS+= commands.c main.c network.c ring.c sys_bsd.c telnet.c terminal.c +DEPSRCS+= tn3270.c utilities.c + +astosc.o: astosc.OUT +CLEANFILES+= astosc.OUT astosc.out +astosc.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/function.h +astosc.OUT: ${.CURDIR}/../ctlr/${KBD} ${.CURDIR}/../tools/mkastosc/obj/mkastosc + ${.CURDIR}/../tools/mkastosc/obj/mkastosc \ + ${.CURDIR}/../ctlr/hostctlr.h \ + ${.CURDIR}/../ctlr/function.h < ${.CURDIR}/../ctlr/${KBD} \ + > ${.TARGET} + rm -f astosc.out; ln -s astosc.OUT astosc.out + +disp_asc.o: asc_disp.OUT disp_asc.OUT +asc_disp.OUT: ${.CURDIR}/../tools/mkastods/obj/mkastods + ${.CURDIR}/../tools/mkastods/obj/mkastods > ${.TARGET} + rm -f asc_disp.out; ln -s asc_disp.OUT asc_disp.out + +disp_asc.OUT: ${.CURDIR}/../tools/mkdstoas/obj/mkdstoas + ${.CURDIR}/../tools/mkdstoas/obj/mkdstoas > ${.TARGET} + rm -f disp_asc.out; ln -s disp_asc.OUT disp_asc.out + +inbound.o: kbd.OUT +CLEANFILES += kbd.OUT kbd.out +kbd.OUT: ${.CURDIR}/../ctlr/hostctlr.h ${.CURDIR}/../ctlr/${KBD} +kbd.OUT: ${.CURDIR}/../tools/mkhits/obj/mkhits + ${CC} ${CFLAGS} -E ${.CURDIR}/../ctlr/function.c > TMPfunc.out + ${.CURDIR}/../tools/mkhits/obj/mkhits ${.CURDIR}/../ctlr/hostctlr.h \ + TMPfunc.out < ${.CURDIR}/../ctlr/${KBD} > ${.TARGET} + rm -f kbd.out; ln -s kbd.OUT kbd.out + +# astosc.out +# asc_disp.out disp_asc.out +# default.map +# kbd.out + +${.CURDIR}/../tools/mkastosc/obj/mkastosc: + cd ${.CURDIR}/../tools/mkastosc; make +${.CURDIR}/../tools/mkastods/obj/mkastods: + cd ${.CURDIR}/../tools/mkastods; make +${.CURDIR}/../tools/mkdstoas/obj/mkdstoas: + cd ${.CURDIR}/../tools/mkdstoas; make +${.CURDIR}/../tools/mkhits/obj/mkhits: + cd ${.CURDIR}/../tools/mkhits; make + +depend: .depend +.depend: ${DEPSRCS} + mkdep ${MKDEP} ${CFLAGS:M-[ID]*} ${.ALLSRC:M*.c} + +.include <../../Makefile.inc> +.include diff --git a/usr.bin/tn3270/tn3270/tn3270.1 b/usr.bin/tn3270/tn3270/tn3270.1 new file mode 100644 index 0000000..778302e --- /dev/null +++ b/usr.bin/tn3270/tn3270/tn3270.1 @@ -0,0 +1,339 @@ +.\" Copyright (c) 1986, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tn3270.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt TN3270 1 +.Os BSD 4.3 +.Sh NAME +.Nm tn3270 +.Nd full-screen remote login to +.Tn IBM VM/CMS +.Sh SYNOPSIS +.Nm tn3270 +.Op Fl d +.Op Fl n Ar filename +.Op Fl t Ar commandname +.Op Ar sysname Op port +.Sh DESCRIPTION +.Nm Tn3270 +permits a full-screen, full-duplex connection +from a +.Tn UNIX +machine +to an +.Tn IBM +(or compatible) machine. +.Nm Tn3270 +gives the appearance of being logged in +to the remote machine +from an +.Tn IBM +3270 terminal. +Of course, you must have an account on the machine +to which you connect in order to log in. +.Nm Tn3270 +looks to the user in many respects +like the Yale +.Tn ASCII +Terminal Communication System II. +.Nm Tn3270 +is actually a modification of the Arpanet +.Tn TELNET +user interface (see +.Xr telnet 1 ) +which will, in certain circumstances, interpret and generate +raw 3270 control streams. +.Pp +The flags to +.Nm tn3270 +are as follows: +.Bl -tag -width Fl +.It Fl d +Turn on socket-level tracing (for super-user only) +.Fl n Ns Ar filename +Specify a file to receive network trace data +output (from commands "toggle netdata" and +"toggle options", see +.Xr telnet 1 ) ; +the default is for output +to be directed to the standard error file. +.Fl t Ns Ar commandname +Specify a +.Tn UNIX +command to process +.Tn IBM +4994 style transparent mode +data received from the remote +.Tn IBM +machine. +.It Ar sysname +The name of the remote system. If the remote name +is NOT specified, the user will be prompted for a +command (see below). +.It Ar port +The port to connect to on the remote system. +Normally, +.Nm tn3270 +attempts to connect to the +standard +.Tn TELNET +port (port +23) on the remote machine. +.El +.Pp +When +.Nm tn3270 +first connects to the remote system, it will negotiate to go into +3270 mode. +Part of this negotiation involves telling the remote system what model +3270 it is emulating. +In all cases, +.Nm tn3270 +emulates a 3278 terminal. +To decide which specific model, +.Nm tn3270 +looks at the number of lines and columns on the actual terminal (as +defined in the +.Ev TERM +environment variable; see +.Xr termcap 5 ) . +The terminal (or window in which +.Nm tn3270 +is running, on multiple +window systems) must have at least 80 columns and 24 lines, or +.Nm tn3270 +will not go into emulation mode. +If the terminal does have at least 80 columns and at least 24 lines, +the following table describes the emulation: +.Pp +.ne 7v +.Bd -filled -offset center +.Bl -column (rows*columns) +.It minimum_size emulated +.It (rows*columns) terminal +.It -------------- ------------ +.It 27*132 3278 model 5 +.It 43*80 3278 model 4 +.It 32*80 3278 model 3 +.It 24*80 3278 model 2. +.El +.Ed +.Pp +Emulation of the 3270 terminal is done in the +.Tn UNIX +process. +This emulation involves mapping +3270-style commands from the host +into appropriate sequences to control the user's terminal screen. +.Nm Tn3270 +uses +.Xr curses 3 +and the +.Pa /usr/share/misc/termcap +file to do this. +The emulation also involves simulating the special 3270 keyboard keys +(program function keys, etc.) +by mapping sequences of keystrokes +from the +.Tn ASCII +keyboard into appropriate 3270 control strings. +This mapping is terminal dependent and is specified +in a description file, +.Pa /usr/share/misc/map3270 , +(see +.Xr map3270 5 ) +or in an environment variable +.Ev MAP3270 +(and, if necessary, +.Ev MAP3270A , +.Ev MAP3270B , +and so on - see +.Xr mset 1 ) . +Any special function keys on the +.Tn ASCII +keyboard are used whenever possible. +If an entry for the user's terminal +is not found, +.Nm tn3270 +looks for an entry for the terminal type +.Em unknown . +If this is not found, +.Nm tn3270 +uses a default keyboard mapping +(see +.Xr map3270 5 ) . +.Pp +The first character of each special keyboard mapping sequence +is either an +.Tn ASCII +escape +.Pq Tn ESC , +a control character, or an +.Tn ASCII +delete +.Pq Tn DEL . +If the user types an unrecognized function key sequence, +.Nm tn3270 +sends an +.Tn ASCII +bell +.Pq Tn BEL , +or a visual bell if +defined in the user's termcap entry, to the user's terminal +and nothing is sent to the +.Tn IBM +host. +.Pp +If +.Nm tn3270 +is invoked without specifying a remote host system name, +it enters local command mode, +indicated by the prompt +.Dq Li tn3270>\ . +In this mode, +.Nm tn3270 +accepts and executes +all the commands of +.Xr telnet 1 , +plus one additional command: +.Pp +.Bl -tag -width Ar +.It Ic transcom +Specify +.Tn UNIX +command for +.Tn IBM +4994 style transparent mode processing. +.El +.Pp +.Nm Tn3270 +command mode may also be entered, after connecting to a host, by typing +a special escape sequence. +If +.Nm tn3270 +has succeeded in negotiating 3270 mode with the remote host, the +escape sequence will be as defined by the map3270 (see +.Xr map3270 5 ) +entry for the user's terminal type +(typically control-C); +otherwise the escape sequence will initially be set to the +single character +.Sq Li \&^] +(control right square bracket). +.Pp +While in command mode, any host login session is still alive +but temporarily suspended. +The host login session may be resumed by entering an empty line +(press the +.Tn RETURN +key) +in response to the command prompt. +A session may be terminated by logging off the foreign host, +or by typing ``quit'' or ``close'' while in local command mode. +.Sh FILES +.Bl -tag -width /usr/share/misc/termcap -compact +.It Pa /usr/share/misc/termcap +.It Pa /usr/share/misc/map3270 +.El +.\" .Sh AUTHOR +.\" Greg Minshall +.Sh NOTES +The +.Tn IBM +4994 style transparent mode command is invoked when +.Nm tn3270 +receives +.Tn IBM +4994 style transparent output from the remote host. +Output and input pipes are created for communication between the two +processes. +The pipes are closed when a 3270 clear command is received from the remote +hosts, signaling the end of transparent mode output. +Transparent mode is necessary for sending +.Tn ASCII +control characters over the +3270 terminal connection; +.Tn ASCII +graphics terminal support is accomplished this +way. +Developers of +.Ic transcom +commands should note that the +.Ic transcom +stdin pipe end will be in +.Dv CBREAK +mode, with +.Dv ECHO +and +.Dv CRMOD +turned off. +.Sh ENVIRONMENT +.Nm Tn3270 +checks the following environment variables: +.Ev TERM , +.Ev MAP3270 , +.Ev MAP3270[A...] . +Information on these can be found in +.Xr mset 1 . +.Nm Tn3270 +also checks +.Ev SHELL , +.Ev KEYBD +and +.Ev API3270 . +.Sh SEE ALSO +.Xr mset 1 , +.Xr telnet 1 , +.Xr curses 3 , +.Xr termcap 3 , +.Xr termcap 5 , +.Xr map3270 5 , +.Rs +.%T "Yale ASCII Terminal Communication" +.%B "System II Program Description/Operator's Manual" +.%R IBM SB30-1911 +.Re +.Sh HISTORY +The +.Nm tn3270 +command appeared in +.Bx 4.3 . +.Sh BUGS +Tn3270 is slow and uses system resources prodigiously. +.Pp +Not all 3270 functions are supported, +nor all Yale enhancements. +.Pp +Error conditions (attempting to enter data in a protected field, for +example) should cause a message to be sent to the user's terminal +instead of just ringing a bell. diff --git a/usr.bin/tn3270/tools/Makefile b/usr.bin/tn3270/tools/Makefile new file mode 100644 index 0000000..0b64f8f --- /dev/null +++ b/usr.bin/tn3270/tools/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +SUBDIR= mkhits mkastosc mkastods mkdstoas mkdctype + +.include diff --git a/usr.bin/tn3270/tools/mkastods/Makefile b/usr.bin/tn3270/tools/mkastods/Makefile new file mode 100644 index 0000000..a2d36a1 --- /dev/null +++ b/usr.bin/tn3270/tools/mkastods/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkastods +SRCS= mkastods.c asc_ebc.c ebc_disp.c +CFLAGS+=-I${.CURDIR}/.. -I. +NOMAN= noman +.PATH: ${.CURDIR}/../../api + +.include diff --git a/usr.bin/tn3270/tools/mkastods/mkastods.c b/usr.bin/tn3270/tools/mkastods/mkastods.c new file mode 100644 index 0000000..6a9f72e --- /dev/null +++ b/usr.bin/tn3270/tools/mkastods/mkastods.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkastods.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include +#include "../api/asc_ebc.h" +#include "../api/ebc_disp.h" + +int +main() +{ + int i; + + /* For each ascii code, find the display code that matches */ + + printf("unsigned char asc_disp[256] = {"); + for (i = 0; i < NASCII; i++) { + if ((i%8) == 0) { + printf("\n"); + } + printf("\t0x%02x,", ebc_disp[asc_ebc[i]]); + } + for (i = sizeof disp_ebc; i < 256; i++) { + if ((i%8) == 0) { + printf("\n"); + } + printf("\t0x%02x,", 0); + } + printf("\n};\n"); + + return 0; +} diff --git a/usr.bin/tn3270/tools/mkastosc/Makefile b/usr.bin/tn3270/tools/mkastosc/Makefile new file mode 100644 index 0000000..a6268f5 --- /dev/null +++ b/usr.bin/tn3270/tools/mkastosc/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkastosc +SRCS= mkastosc.c dohits.c asc_ebc.c ebc_disp.c +CFLAGS+=-I${.CURDIR}/../mkhits -I${.CURDIR}/.. -I. +NOMAN= noman +.PATH: ${.CURDIR}/../mkhits ${.CURDIR}/../../api + +.include diff --git a/usr.bin/tn3270/tools/mkastosc/mkastosc.c b/usr.bin/tn3270/tools/mkastosc/mkastosc.c new file mode 100644 index 0000000..697122d --- /dev/null +++ b/usr.bin/tn3270/tools/mkastosc/mkastosc.c @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkastosc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include + +#include "../general/general.h" +#include "../ctlr/function.h" + +#include "dohits.h" + +static struct tbl { + unsigned char + scancode, + used; + char + *shiftstate; +} tbl[128]; + +int +main(argc, argv) +int argc; +char *argv[]; +{ + int scancode; + int asciicode; + int empty; + int i; + int c; + int found; + struct hits *ph; + struct Hits *Ph; + struct thing *this; + struct thing **attable; + struct tbl *Pt; + static char *shiftof[] = + { "0", "SHIFT_UPSHIFT", "SHIFT_ALT", "SHIFT_ALT|SHIFT_UPSHIFT" }; + char *aidfile = 0, *fcnfile = 0; + + if (argc > 1) { + if (argv[1][0] != '-') { + aidfile = argv[1]; + } + } + if (argc > 2) { + if (argv[2][0] != '-') { + fcnfile = argv[2]; + } + } + + dohits(aidfile, fcnfile); /* Set up "Hits" */ + + printf("/*\n"); + printf(" * Ascii to scancode conversion table. First\n"); + printf(" * 128 bytes (0-127) correspond with actual Ascii\n"); + printf(" * characters; the rest are functions from ctrl/function.h\n"); + printf(" */\n"); + /* Build the ascii part of the table. */ + for (Ph = Hits, scancode = 0; Ph <= Hits+highestof(Hits); + Ph++, scancode++) { + ph = &Ph->hits; + for (i = 0; i < 4; i++) { + if (ph->hit[i].ctlrfcn == FCN_CHARACTER) { + c = Ph->name[i][0]; /* "name" of this one */ + if (tbl[c].used == 0) { + tbl[c].used = 1; + tbl[c].shiftstate = shiftof[i]; + tbl[c].scancode = scancode; + } + } + } + } + /* Now, output the table */ + for (Pt = tbl, asciicode = 0; Pt <= tbl+highestof(tbl); Pt++, asciicode++) { + if (Pt->used == 0) { + if (isprint(asciicode) && (asciicode != ' ')) { + fprintf(stderr, "Unable to produce scancode sequence for"); + fprintf(stderr, " ASCII character [%c]!\n", asciicode); + } + printf("\t{ 0, 0, undefined, 0 },\t"); + } else { + printf("\t{ 0x%02x, %s, FCN_CHARACTER, 0 },", + Pt->scancode, Pt->shiftstate); + } + printf("\t/* 0x%x", asciicode); + if (isprint(asciicode)) { + printf(" [%c]", asciicode); + } + printf(" */\n"); + } + + + for (attable = &table[0]; attable <= &table[highestof(table)]; attable++) { + for (this = *attable; this; this = this->next) { + Ph = this->hits; + if (Ph == 0) { + continue; + } + for (i = 0; i < 4; i++) { + if ((Ph->name[i] != 0) && + (Ph->name[i][0] == this->name[0]) && + (strcmp(Ph->name[i], this->name) == 0)) { + printf("\t{ 0x%02x, %s, ", + Ph-Hits, shiftof[i]); + if (memcmp("AID_", this->name, 4) == 0) { /* AID key */ + printf("FCN_AID, "); + } else { + printf("%s, ", Ph->name[i]); + } + if (memcmp("PF", this->name+4, 2) == 0) { + printf("\"PFK%s\" },\n", Ph->name[i]+4+2); + } else { + printf("\"%s\" },\n", Ph->name[i]+4); + } + } + } + } + } + + return 0; +} diff --git a/usr.bin/tn3270/tools/mkdctype/Makefile b/usr.bin/tn3270/tools/mkdctype/Makefile new file mode 100644 index 0000000..818bb52 --- /dev/null +++ b/usr.bin/tn3270/tools/mkdctype/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkdctype +SRCS= mkdctype.c ebc_disp.c ectype.c +CFLAGS+=-I${.CURDIR}/.. -I. +NOMAN= noman +.PATH: ${.CURDIR}/../../api + +.include diff --git a/usr.bin/tn3270/tools/mkdctype/ectype.c b/usr.bin/tn3270/tools/mkdctype/ectype.c new file mode 100644 index 0000000..ebdca0b --- /dev/null +++ b/usr.bin/tn3270/tools/mkdctype/ectype.c @@ -0,0 +1,313 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)ectype.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ectype.h" + +char ectype[] = { +/* 0x00 */ + E_SPACE, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0x10 */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0x20 */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0x30 */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0x40 */ + E_SPACE, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, +/* 0x50 */ + E_PRINT|E_PUNCT, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, +/* 0x60 */ + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, +/* 0x70 */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, + E_PRINT|E_PUNCT, +/* 0x80 */ + 0x00, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0x90 */ + 0x00, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xA0 */ + 0x00, + E_PRINT|E_PUNCT, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + E_PRINT|E_LOWER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xB0 */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xC0 */ + E_PRINT|E_PUNCT, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xD0 */ + E_PRINT|E_PUNCT, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xE0 */ + E_PRINT|E_PUNCT, + 0x00, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + E_PRINT|E_UPPER, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +/* 0xF0 */ + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + E_PRINT|E_DIGIT, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; diff --git a/usr.bin/tn3270/tools/mkdctype/ectype.h b/usr.bin/tn3270/tools/mkdctype/ectype.h new file mode 100644 index 0000000..15dfb86 --- /dev/null +++ b/usr.bin/tn3270/tools/mkdctype/ectype.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)ectype.h 8.1 (Berkeley) 6/6/93 + */ + +#define INCLUDED_ECTYPE + +#define E_UPPER 0x01 +#define E_LOWER 0x02 +#define E_DIGIT 0x04 +#define E_SPACE 0x08 +#define E_PUNCT 0x10 +#define E_PRINT 0x20 + +#define Eisalpha(c) (ectype[(c)&0xff]&(E_UPPER|E_LOWER)) +#define Eisupper(c) (ectype[(c)&0xff]&E_UPPER) +#define Eislower(c) (ectype[(c)&0xff]&E_LOWER) +#define Eisdigit(c) (ectype[(c)&0xff]&E_DIGIT) +#define Eisalnum(c) (ectype[(c)&0xff]&(E_UPPER|E_LOWER|E_DIGIT)) +#define Eisspace(c) (ectype[(c)&0xff]&E_SPACE) /* blank or null */ +#define Eispunct(c) (ectype[(c)&0xff]&E_PUNCT) +#define Eisprint(c) (ectype[(c)&0xff]&E_PRINT) diff --git a/usr.bin/tn3270/tools/mkdctype/mkdctype.c b/usr.bin/tn3270/tools/mkdctype/mkdctype.c new file mode 100644 index 0000000..24ee095 --- /dev/null +++ b/usr.bin/tn3270/tools/mkdctype/mkdctype.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkdctype.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "../api/ebc_disp.h" +#include "ectype.h" + + +extern unsigned char ectype[256]; + + +void +main() +{ + static unsigned char dctype[192] = { 0 }; + int i; + char *orbar; + int type; + + for (i = 0; i < sizeof ectype; i++) { + dctype[ebc_disp[i]] = ectype[i]; + } + + for (i = 0; i < sizeof dctype; i++) { + if ((i%16) == 0) { + printf("/*%02x*/\n", i); + } + printf("\t"); + type = dctype[i]; + orbar = ""; + if (type & E_UPPER) { + printf("E_UPPER"); + orbar = "|"; + } + if (type & E_LOWER) { + printf("%sD_LOWER", orbar); + orbar = "|"; + } + if (type & E_DIGIT) { + printf("%sD_DIGIT", orbar); + orbar = "|"; + } + if (type & E_SPACE) { + printf("%sD_SPACE", orbar); + orbar = "|"; + } + if (type & E_PUNCT) { + printf("%sD_PUNCT", orbar); + orbar = "|"; + } + if (type & E_PRINT) { + printf("%sD_PRINT", orbar); + orbar = "|"; + } + if (orbar[0] == 0) { + printf("0"); + } + printf(",\n"); + } +} diff --git a/usr.bin/tn3270/tools/mkdstoas/Makefile b/usr.bin/tn3270/tools/mkdstoas/Makefile new file mode 100644 index 0000000..b2abeb3 --- /dev/null +++ b/usr.bin/tn3270/tools/mkdstoas/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkdstoas +SRCS= mkdstoas.c asc_ebc.c ebc_disp.c +CFLAGS+=-I${.CURDIR}/.. -I. +NOMAN= noman +.PATH: ${.CURDIR}/../../api + +.include diff --git a/usr.bin/tn3270/tools/mkdstoas/mkdstoas.c b/usr.bin/tn3270/tools/mkdstoas/mkdstoas.c new file mode 100644 index 0000000..befd3c6 --- /dev/null +++ b/usr.bin/tn3270/tools/mkdstoas/mkdstoas.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkdstoas.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include +#include "../api/asc_ebc.h" +#include "../api/ebc_disp.h" + + +int +main() +{ + int i; + + /* For each display code, find the ascii code that matches */ + + printf("unsigned char disp_asc[256] = {"); + for (i = 0; i < sizeof disp_ebc; i++) { + if ((i%8) == 0) { + printf("\n"); + } + printf("\t0x%02x,", ebc_asc[disp_ebc[i]]); + } + for (i = sizeof disp_ebc; i < 256; i++) { + if ((i%8) == 0) { + printf("\n"); + } + printf("\t0x%02x,", ' '); + } + printf("\n};\n"); + + return 0; +} diff --git a/usr.bin/tn3270/tools/mkhits/Makefile b/usr.bin/tn3270/tools/mkhits/Makefile new file mode 100644 index 0000000..c7c8802 --- /dev/null +++ b/usr.bin/tn3270/tools/mkhits/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mkhits +SRCS= mkhits.c dohits.c asc_ebc.c ebc_disp.c +CFLAGS+=-I${.CURDIR}/.. -I. +NOMAN= noman +.PATH: ${.CURDIR}/../../api + +.include diff --git a/usr.bin/tn3270/tools/mkhits/dohits.c b/usr.bin/tn3270/tools/mkhits/dohits.c new file mode 100644 index 0000000..d2d576e --- /dev/null +++ b/usr.bin/tn3270/tools/mkhits/dohits.c @@ -0,0 +1,295 @@ +/*- + * Copyright (c) 1988, 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[] = "@(#)dohits.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This program scans a file which describes a keyboard. The output + * of the program is a series of 'C' declarations which describe a + * mapping between (scancode, shiftstate, altstate) and 3270 functions, + * characters, and AIDs. + * + * The format of the input file is as follows: + * + * keynumber [ scancode [ unshifted [ shifted [ alted [ shiftalted ] ] ] ] ] + * + * keynumber is in decimal, and starts in column 1. + * scancode is hexadecimal. + * unshifted, etc. - these are either a single ascii character, + * or the name of a function or an AID-generating key. + * + * all fields are separated by a single space. + */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include +#include "../general/general.h" +#include "../api/asc_ebc.h" +#include "../api/ebc_disp.h" +#include "../ctlr/function.h" + +#include "dohits.h" + +struct Hits Hits[256]; /* one for each of 0x00-0xff */ + +struct thing *table[100]; + +extern char *malloc(); + +unsigned int +dohash(seed, string) +unsigned int seed; +char *string; +{ + register unsigned int i = seed; + register unsigned char c; + + while (c = *string++) { + if (c >= 0x60) { + c -= (0x60+0x20); + } else { + c -= 0x20; + } + i = (i>>26) + (i<<6) + (c&0x3f); + } + return i; +} + +void +add(first, second, value) +char *first, *second; +int value; +{ + struct thing **item, *this; + + item = &firstentry(second); + this = (struct thing *) malloc(sizeof *this); + this->next = *item; + *item = this; + this->value = value; + strcpy(this->name, first); + strcpy(this->name+strlen(this->name), second); +} + +void +scanwhite(file, prefix) +char *file, /* Name of file to scan for whitespace prefix */ + *prefix; /* prefix of what should be picked up */ +{ + FILE *ourfile; + char compare[100]; + char what[100], value[100]; + char line[200]; + + sprintf(compare, " %s%%[^,\t \n]", prefix); + if ((ourfile = fopen(file, "r")) == NULL) { + perror("fopen"); + exit(1); + } + while (!feof(ourfile)) { + if (fscanf(ourfile, compare, what) == 1) { + add(prefix, what, 0); + } + do { + if (fgets(line, sizeof line, ourfile) == NULL) { + if (!feof(ourfile)) { + perror("fgets"); + } + break; + } + } while (line[strlen(line)-1] != '\n'); + } +} + +void +scandefine(file, prefix) +char *file, /* Name of file to scan for #define prefix */ + *prefix; /* prefix of what should be picked up */ +{ + FILE *ourfile; + char compare[100]; + char what[100], value[100]; + char line[200]; + int whatitis; + + sprintf(compare, "#define %s%%s %%s", prefix); + if ((ourfile = fopen(file, "r")) == NULL) { + perror("fopen"); + exit(1); + } + while (!feof(ourfile)) { + if (fscanf(ourfile, compare, what, value) == 2) { + if (value[0] == '0') { + if ((value[1] == 'x') || (value[1] == 'X')) { + sscanf(value, "0x%x", &whatitis); + } else { + sscanf(value, "0%o", &whatitis); + } + } else { + sscanf(value, "%d", &whatitis); + } + add(prefix, what, whatitis); + } + do { + if (fgets(line, sizeof line, ourfile) == NULL) { + if (!feof(ourfile)) { + perror("fgets"); + } + break; + } + } while (line[strlen(line)-1] != '\n'); + } +} + +char *savechr(c) +unsigned char c; +{ + char *foo; + + foo = malloc(sizeof c); + if (foo == 0) { + fprintf(stderr, "No room for ascii characters!\n"); + exit(1); + } + *foo = c; + return foo; +} + +char * +doit(hit, type, hits) +struct hit *hit; +unsigned char *type; +struct Hits *hits; +{ + struct thing *this; + + hit->ctlrfcn = FCN_NULL; + if (type[0] == 0) { + return 0; + } + if (type[1] == 0) { /* character */ + hit->ctlrfcn = FCN_CHARACTER; + hit->code = ebc_disp[asc_ebc[type[0]]]; + return savechr(*type); /* The character is the name */ + } else { + for (this = firstentry(type); this; this = this->next) { + if ((type[0] == this->name[4]) + && (strcmp(type, this->name+4) == 0)) { + this->hits = hits; + if (this->name[0] == 'F') { + hit->ctlrfcn = FCN_NULL; /* XXX */ + } else { + hit->ctlrfcn = FCN_AID; + } + return this->name; + } + } + fprintf(stderr, "Error: Unknown type %s.\n", type); + return 0; + } +} + + +void +dohits(aidfile, fcnfile) +char *aidfile, *fcnfile; +{ + unsigned char plain[100], shifted[100], alted[100], shiftalted[100]; + unsigned char line[200]; + int keynumber, scancode; + int empty; + int i; + struct hit *hit; + struct hits *ph; + struct Hits *Ph; + + memset((char *)Hits, 0, sizeof Hits); + + /* + * First, we read "host3270.h" to find the names/values of + * various AID; then we read kbd3270.h to find the names/values + * of various FCNs. + */ + + if (aidfile == 0) { + aidfile = "../ctlr/hostctlr.h"; + } + scandefine(aidfile, "AID_"); + if (fcnfile == 0) { + fcnfile = "../ctlr/function.h"; + } + scanwhite(fcnfile, "FCN_"); + + while (gets(line) != NULL) { + if (!isdigit(line[0])) { + continue; + } + plain[0] = shifted[0] = alted[0] = shiftalted[0] = 0; + keynumber = -1; + scancode = -1; + (void) sscanf(line, "%d %x %s %s %s %s", &keynumber, + &scancode, plain, shifted, alted, shiftalted); + if ((keynumber == -1) || (scancode == -1) + || ((plain[0] == 0) + && (shifted[0] == 0) + && (alted[0] == 0) + && (shiftalted[0] == 0))) { + continue; + } + if (scancode >= 256) { + fprintf(stderr, + "Error: scancode 0x%02x for keynumber %d\n", scancode, + keynumber); + break; + } + if (Hits[scancode].hits.hit[0].ctlrfcn != undefined) { + fprintf(stderr, + "Error: duplicate scancode 0x%02x for keynumber %d\n", + scancode, keynumber); + break; + } + hit = Hits[scancode].hits.hit; + Hits[scancode].hits.keynumber = keynumber; + Hits[scancode].name[0] = doit(hit, plain, &Hits[scancode]); + Hits[scancode].name[1] = doit(hit+1, shifted, &Hits[scancode]); + Hits[scancode].name[2] = doit(hit+2, alted, &Hits[scancode]); + Hits[scancode].name[3] = doit(hit+3, shiftalted, &Hits[scancode]); + } +} diff --git a/usr.bin/tn3270/tools/mkhits/dohits.h b/usr.bin/tn3270/tools/mkhits/dohits.h new file mode 100644 index 0000000..9c26eca --- /dev/null +++ b/usr.bin/tn3270/tools/mkhits/dohits.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1988, 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. + * + * @(#)dohits.h 8.1 (Berkeley) 6/6/93 + */ + +#define numberof(x) (sizeof x/sizeof x[0]) +#define highestof(x) (numberof(x)-1) + +#define firstentry(x) (table[dohash(0, (x))%highestof(table)]) + +struct Hits { + struct hits hits; + char *name[4]; +}; + +struct thing { + struct thing *next; + struct Hits *hits; + unsigned char value; + char name[100]; +}; + +extern struct Hits Hits[256]; /* one for each of 0x00-0xff */ +extern struct thing *table[100]; + +extern unsigned int dohash(); diff --git a/usr.bin/tn3270/tools/mkhits/mkhits.c b/usr.bin/tn3270/tools/mkhits/mkhits.c new file mode 100644 index 0000000..0fafb8f --- /dev/null +++ b/usr.bin/tn3270/tools/mkhits/mkhits.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkhits.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * This program scans a file which describes a keyboard. The output + * of the program is a series of 'C' declarations which describe a + * mapping between (scancode, shiftstate, altstate) and 3270 functions, + * characters, and AIDs. + * + * The format of the input file is as follows: + * + * keynumber [ scancode [ unshifted [ shifted [ alted [ shiftalted ] ] ] ] ] + * + * keynumber is in decimal, and starts in column 1. + * scancode is hexadecimal. + * unshifted, etc. - these are either a single ascii character, + * or the name of a function or an AID-generating key. + * + * all fields are separated by a single space. + */ + +#include +#if defined(unix) +#include +#else /* defined(unix) */ +#include +#endif /* defined(unix) */ +#include +#include "../ctlr/function.h" + +#include "dohits.h" + + +int +main(argc, argv) +int argc; +char *argv[]; +{ + int scancode; + int empty; + int i; + struct hits *ph; + struct Hits *Ph; + char *aidfile = 0, *fcnfile = 0; + + if (argc > 1) { + if (argv[1][0] != '-') { + aidfile = argv[1]; + } + } + if (argc > 2) { + if (argv[2][0] != '-') { + fcnfile = argv[2]; + } + } + + dohits(aidfile, fcnfile); /* Set up "Hits" */ + + printf("struct hits hits[] = {\n"); + empty = 0; + scancode = -1; + for (Ph = Hits; Ph < Hits+(sizeof Hits/sizeof Hits[0]); Ph++) { + ph = &Ph->hits; + scancode++; + if ((ph->hit[0].ctlrfcn == undefined) + && (ph->hit[1].ctlrfcn == undefined) + && (ph->hit[2].ctlrfcn == undefined) + && (ph->hit[3].ctlrfcn == undefined)) { + empty++; + continue; + } else { + while (empty) { + printf("\t{ 0, { {undefined}, {undefined}"); + printf(", {undefined}, {undefined} } },\n"); + empty--; + } + } + printf("\t{ %d, {\t/* 0x%02x */\n\t", ph->keynumber, scancode); + for (i = 0; i < 4; i++) { + printf("\t{ "); + switch (ph->hit[i].ctlrfcn) { + case undefined: + printf("undefined"); + break; + case FCN_CHARACTER: + printf("FCN_CHARACTER, 0x%02x", ph->hit[i].code); + break; + case FCN_AID: + printf("FCN_AID, %s", Ph->name[i]); + break; + case FCN_NULL: + default: + if ((Ph->name[i] != 0) + && (strcmp(Ph->name[i], "FCN_NULL") != 0)) { + printf("%s", Ph->name[i]); + } else { + printf("undefined"); + } + break; + } + printf(" },\n\t"); + } + printf("} },\n"); + } + printf("};\n"); + return 0; +} diff --git a/usr.bin/tn3270/tools/mkmake.y b/usr.bin/tn3270/tools/mkmake.y new file mode 100644 index 0000000..e9c2c6b --- /dev/null +++ b/usr.bin/tn3270/tools/mkmake.y @@ -0,0 +1,1097 @@ +%{ + +/*- + * Copyright (c) 1988, 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[] = "@(#)mkmake.y 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +typedef struct string { + int + hashval, + length; + char + *string; + struct string + *next; +} string_t; + +/* + * The deal with these is that they exist on various lists. + * + * First off, they are on a temporary list during the time they + * are in the active focus of the parser. + * + * Secondly, they live on one of three queues: + * 1. Variables + * 2. Targets + * 3. Actions + * (and, we restrict any given one to live on one and only one such list) + * + * Also, they may live on the list of values for someone else's variable, + * or as someone's dependancy. + */ + +typedef struct same { + string_t + *string; /* My name */ + struct same + *nexttoken, /* Next pointer */ + *lasttoken, /* Back pointer */ + *depend_list, /* If target, dependancies */ + *action_list, /* If target, actions */ + *value_list, /* If variable, value list */ + *shell_item; /* If a shell variable, current value */ +} same_t; + +%} + +%union { + string_t *string; + same_t *same; + int intval; + } + +%start makefile +%token TOKEN QUOTED_STRING +%token FOR IN DO DONE +%token MACRO_CHAR NL WHITE_SPACE +%token ':' '=' '$' '{' '}' ';' '-' '@' '(' ')' ' ' '\t' +%type target target1 assignment assign1 actions action +%type command_list list list_element +%type for_statement maybe_at_minus tokens token +%type maybe_white_space +%type white_space macro_char +%% + +makefile : lines; + +lines : line + | lines line + ; + +line : NL + | assignment + | target_action + ; + +assignment : assign1 tokens NL + { + assign($1, $2); + } + | assign1 NL + { + assign($1, same_copy(null)); + } + ; + +assign1: token maybe_white_space '=' maybe_white_space + ; + +target_action: target actions + { + add_targets_actions($1, $2); + } + | target + { + add_targets_actions($1, 0); + } + ; + +target : target1 tokens NL + { + $$ = add_depends($1, $2); + } + | target1 NL + { + $$ = add_depends($1, same_copy(null)); + } + ; + +target1: tokens maybe_white_space ':' maybe_white_space + { + $$ = ws_merge($1); + } + ; + +actions: action + | actions action + { + $$ = same_cat(same_cat($1, same_copy(newline)), $2); + } + ; + +action: white_space command_list NL + { + $$ = $2; + } + | white_space for_statement do command_list semi_colon done NL + { + $$ = do_command($2, $4); + } + ; + +for_statement: maybe_at_minus FOR white_space token + in tokens semi_colon + { + $$ = for_statement($1, $4, ws_merge(expand_variables($6, 0))); + } + ; + +in: white_space IN white_space +do: white_space DO white_space + ; + +done: white_space DONE + ; + +semi_colon: ';' + ; + +command_list: list + | '(' list maybe_white_space ')' + { + $$ = same_cat($2, same_copy(cwd_line)); + } + ; + +list: token + | list list_element + { + $$ = same_cat($1, $2); + } + | list white_space list_element + { + $$ = same_cat($1, same_cat(same_copy(blank), $3)); + } + ; + +list_element: token + | semi_colon + { + $$ = same_copy(newline); + } + ; + +maybe_at_minus: /* empty */ + { + $$ = same_copy(null); + } + | '@' + { + char buffer[2]; + + buffer[0] = $1; + buffer[1] = 0; + $$ = same_item(string_lookup(buffer)); + } + | '-' + { + char buffer[2]; + + buffer[0] = $1; + buffer[1] = 0; + $$ = same_item(string_lookup(buffer)); + } + ; + +tokens : token + | tokens maybe_white_space token + { + $$ = same_cat($1, same_cat($2, $3)); + } + ; + +token: TOKEN + { + $$ = same_item($1); + } + | QUOTED_STRING + { + $$ = same_item($1); + } + | '$' macro_char + { + char buffer[3]; + + buffer[0] = '$'; + buffer[1] = $2; + buffer[2] = 0; + + $$ = same_item(string_lookup(buffer)); + } + | '$' '$' TOKEN + { + $$ = shell_variable(same_item($3)); + } + | MACRO_CHAR + { + $$ = same_char($1); + } + | '$' '{' TOKEN '}' + { + $$ = variable(same_item($3)); + } + | '$' '(' TOKEN ')' + { + $$ = variable(same_item($3)); + } + | '$' TOKEN + { + $$ = variable(same_item($2)); + } + | '-' + { + $$ = same_char('-'); + } + | '@' + { + $$ = same_char('@'); + } + ; + +macro_char: MACRO_CHAR + | '@' + ; + +maybe_white_space: + { + $$ = same_copy(null); + } + | white_space + { + $$ = same_char($1); + } + ; + +white_space : WHITE_SPACE + | white_space WHITE_SPACE + ; +%% +#include +#include + +static int last_char, last_saved = 0; +static int column = 0, lineno = 1; + + +static string_t + *strings = 0; + +static same_t + *shell_variables = 0, + *shell_special = 0, + *variables = 0, + *targets = 0, + *actions = 0; + +static same_t + *null, + *blank, + *cwd_line, + *newline; + +extern char *malloc(); + +static unsigned int + clock = -1; + +struct { + same_t *first; + int next; +} visit_stack[20]; /* 20 maximum */ + +#define visit(what,via) \ + (visit_stack[++clock].next = 0, visit_stack[clock].first = via = what) +#define visited(via) (visitcheck(via) || ((via) == 0) \ + || (visit_stack[clock].next && (via == visit_stack[clock].first))) +#define visit_next(via) (visit_stack[clock].next = 1, (via) = (via)->nexttoken) +#define visit_end() (clock--) + +yyerror(s) +char *s; +{ + fprintf(stderr, "line %d, character %d: %s\n", lineno, column, s); + do_dump(); +} + +int +visitcheck(same) +same_t *same; +{ + if (same->string == 0) { + yyerror("BUG - freed 'same' in use..."); + exit(1); + } + return 0; +} + +int +string_hashof(string, length) +char *string; +int length; +{ + register int i = 0; + + while (length--) { + i = (i<<3) + *string ^ ((i>>28)&0x7); + } + return i; +} + +int +string_same(s1, s2) +string_t + *s1, *s2; +{ + if ((s1->hashval == s2->hashval) && (s1->length == s2->length) + && (memcmp(s1->string, s2->string, s1->length) == 0)) { + return 1; + } else { + return 0; + } +} + +string_t * +string_lookup(string) +char *string; +{ + string_t ours; + string_t *ptr; + + ours.length = strlen(string); + ours.hashval = string_hashof(string, ours.length); + ours.string = string; + + for (ptr = strings; ptr; ptr = ptr->next) { + if (string_same(&ours, ptr)) { + return ptr; + } + } + if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) { + fprintf(stderr, "No space to add string *%s*!\n", string); + exit(1); + } + ptr->hashval = ours.hashval; + ptr->length = ours.length; + if ((ptr->string = malloc(ours.length+1)) == 0) { + fprintf(stderr, "No space to add literal *%s*!\n", string); + exit(1); + } + memcpy(ptr->string, string, ours.length+1); + ptr->next = strings; + strings = ptr; + return ptr; +} + +#define same_singleton(s) ((s)->nexttoken == (s)) + +same_t * +same_search(list, token) +same_t + *list, + *token; +{ + same_t *ptr; + + ptr = list; + for (visit(list, ptr); !visited(ptr); visit_next(ptr)) { + string_t *string; + + string = ptr->string; + if (string_same(string, token->string)) { + visit_end(); + return ptr; + } + } + visit_end(); + return 0; +} + +same_t * +same_cat(list, tokens) +same_t + *list, + *tokens; +{ + same_t *last; + + if (tokens == 0) { + return list; + } + if (list) { + last = tokens->lasttoken; + tokens->lasttoken = list->lasttoken; + list->lasttoken = last; + tokens->lasttoken->nexttoken = tokens; + last->nexttoken = list; + return list; + } else { + return tokens; + } +} + +same_t * +same_item(string) +string_t *string; +{ + same_t *ptr; + + if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) { + fprintf(stderr, "No more space for tokens!\n"); + exit(1); + } + memset((char *)ptr, 0, sizeof *ptr); + ptr->nexttoken = ptr->lasttoken = ptr; + ptr->string = string; + return ptr; +} + +same_t * +same_copy(same) +same_t *same; +{ + same_t *head, *copy; + + head = 0; + for (visit(same, copy); !visited(copy); visit_next(copy)) { + same_t *ptr; + + ptr = same_item(copy->string); + head = same_cat(head, ptr); + } + visit_end(); + return head; +} + + +same_t * +same_merge(t1, t2) +same_t + *t1, + *t2; +{ + if (same_singleton(t1) && same_singleton(t2)) { + int length = strlen(t1->string->string)+strlen(t2->string->string); + char *buffer = malloc(length+1); + same_t *value; + + if (buffer == 0) { + yyerror("No space to merge strings in same_merge!"); + exit(1); + } + strcpy(buffer, t1->string->string); + strcat(buffer, t2->string->string); + value = same_item(string_lookup(buffer)); + free(buffer); + return value; + } else { + yyerror("Internal error - same_merge with non-singletons"); + exit(1); + } +} + + +void +same_free(list) +same_t *list; +{ + same_t *token, *ptr; + + if (list == 0) { + return; + } + + token = list; + do { + ptr = token->nexttoken; + token->string = 0; + (void) free((char *)token); + token = ptr; + } while (token != list); +} + +same_t * +same_unlink(token) +same_t + *token; +{ + same_t *tmp; + + if (token == 0) { + return 0; + } + if ((tmp = token->nexttoken) == token) { + tmp = 0; + } + token->lasttoken->nexttoken = token->nexttoken; + token->nexttoken->lasttoken = token->lasttoken; + token->nexttoken = token->lasttoken = token; + return tmp; +} + +void +same_replace(old, new) +same_t + *old, + *new; +{ + new->lasttoken->nexttoken = old->nexttoken; + old->nexttoken->lasttoken = new->lasttoken; + new->lasttoken = old->lasttoken; + /* rather than + * old->lasttoken->nexttoken = new + * we update in place (for the case where there isn't anything else) + */ + *old = *new; +} + + +same_t * +same_char(ch) +char ch; +{ + char buffer[2]; + + buffer[0] = ch; + buffer[1] = 0; + + return same_item(string_lookup(buffer)); +} + + +void +add_target(target, actions) +same_t + *target, + *actions; +{ + same_t *ptr; + + if ((ptr = same_search(targets, target)) == 0) { + targets = same_cat(targets, target); + ptr = target; + } else { + ptr->depend_list = same_cat(ptr->depend_list, target->depend_list); + } + if (actions) { + if (ptr->action_list) { + same_free(ptr->action_list); + } + ptr->action_list = same_copy(actions); + } +} + + +same_t * +add_targets_actions(target, actions) +same_t + *target, + *actions; +{ + same_t *ptr; + + if (target == 0) { + return 0; + } + do { + ptr = same_unlink(target); + add_target(target, actions); + target = ptr; + } while (target); + + same_free(actions); + return 0; +} + +same_t * +add_depends(target, depends) +same_t + *target, + *depends; +{ + same_t *original = target; + + depends = same_cat(depends, same_copy(blank)); /* Separator */ + + for (visit(original, target); !visited(target); visit_next(target)) { + target->depend_list = same_cat(target->depend_list, same_copy(depends)); + } + visit_end(); + same_free(depends); + + return original; +} + + +/* + * We know that variable is a singleton + */ + +void +assign(variable, value) +same_t + *variable, + *value; +{ + same_t *ptr; + + if ((ptr = same_search(variables, variable)) != 0) { + same_free(ptr->value_list); + variables = same_unlink(ptr); + same_free(ptr); + } + variable->value_list = value; + variables = same_cat(variables, variable); +} + +same_t * +value_of(variable) +same_t *variable; +{ + same_t *ptr = same_search(variables, variable); + + if (ptr == 0) { + return same_copy(null); + } else { + return same_copy(ptr->value_list); + } +} + + +same_t * +expand_variables(token, free) +same_t *token; +int free; +{ + same_t *head = 0; + + if (!free) { + token = same_copy(token); /* Get our private copy */ + } + + while (token) { + char *string = token->string->string; + same_t *tmp = same_unlink(token); + + if ((string[0] == '$') && (string[1] == '{')) { /* Expand time */ + int len = strlen(string); + + string[len-1] = 0; + head = same_cat(head, expand_variables( + value_of(same_item(string_lookup(string+2))), 1)); + string[len-1] = '}'; + } else { + head = same_cat(head, token); + } + token = tmp; + } + return head; +} + + +same_t * +ws_merge(list) +same_t *list; +{ + same_t *newlist = 0, *item; + int what = 0; + + while (list) { + switch (what) { + case 0: + if (isspace(list->string->string[0])) { + ; + } else { + item = same_item(list->string); + what = 1; + } + break; + case 1: + if (isspace(list->string->string[0])) { + newlist = same_cat(newlist, item); + item = 0; + what = 0; + } else { + item = same_merge(item, same_item(list->string)); + what = 1; + } + break; + } + list = same_unlink(list); + } + return same_cat(newlist, item); +} + + +same_t * +variable(var_name) +same_t *var_name; +{ + int length = strlen(var_name->string->string); + same_t *resolved; + char *newname; + + if ((newname = malloc(length+1+3)) == 0) { + fprintf("Out of space for a variable name.\n"); + exit(1); + } + newname[0] = '$'; + newname[1] = '{'; + strcpy(newname+2, var_name->string->string); + strcat(newname, "}"); + resolved = same_item(string_lookup(newname)); + free(newname); + + return resolved; +} + + +same_t * +shell_variable(var_name) +same_t *var_name; +{ + int length = strlen(var_name->string->string); + same_t *resolved; + char *newname; + + if ((newname = malloc(length+1+2)) == 0) { + fprintf("Out of space for a variable name.\n"); + exit(1); + } + newname[0] = '$'; + newname[1] = '$'; + strcpy(newname+2, var_name->string->string); + resolved = same_item(string_lookup(newname)); + free(newname); + + return resolved; +} + +same_t * +for_statement(special, variable, list) +same_t + *special, + *variable, + *list; +{ + variable->shell_item = special; + variable->value_list = list; + return variable; +} + +same_t * +do_command(forlist, commands) +same_t + *forlist, + *commands; +{ + same_t + *special, + *command_list = 0, + *new_commands, + *tmp, + *shell_item, + *value_list = forlist->value_list; + char + *tmpstr, + *variable_name = forlist->string->string; + + special = forlist->shell_item; + if (same_unlink(forlist->shell_item) != 0) { + yyerror("Unexpected second item in special part of do_command"); + exit(1); + } + + while ((shell_item = value_list) != 0) { + value_list = same_unlink(shell_item); + /* Visit each item in commands. For each shell variable which + * matches ours, replace it with ours. + */ + new_commands = same_copy(commands); + for (visit(new_commands, tmp); !visited(tmp); visit_next(tmp)) { + tmpstr = tmp->string->string; + if ((tmpstr[0] == '$') && (tmpstr[1] == '$')) { + if (strcmp(tmpstr+2, variable_name) == 0) { + same_replace(tmp, same_copy(shell_item)); + } + } + } + visit_end(); + command_list = same_cat(command_list, new_commands); + } + return same_cat(command_list, same_copy(newline)); +} + + +int +Getchar() +{ + if (last_saved) { + last_saved = 0; + return last_char; + } else { + int c; + c = getchar(); + switch (c) { + case '\n': + lineno++; + column = 0; + break; + default: + column++; + } + return c; + } +} + + +int +token_type(string) +char *string; +{ + switch (string[0]) { + case 'f': + if (strcmp(string, "for") == 0) { + return FOR; + } + break; + case 'd': + if (string[1] == 'o') { + if (strcmp(string, "do") == 0) { + return DO; + } else if (strcmp(string, "done") == 0) { + return DONE; + } + } + break; + case 'i': + if (strcmp(string, "in") == 0) { + return IN; + } + break; + default: + break; + } + return TOKEN; +} + + +yylex() +{ +#define ret_token(c) if (bufptr != buffer) { \ + save(c); \ + *bufptr = 0; \ + bufptr = buffer; \ + yylval.string = string_lookup(buffer); \ + return token_type(buffer); \ + } +#define save(c) { last_char = c; last_saved = 1; } +#if defined(YYDEBUG) +#define Return(c) if (yydebug) { \ + printf("[%d]", c); \ + fflush(stdout); \ + } \ + yyval.intval = c; \ + return c; +#else /* defined(YYDEBUG) */ +#define Return(y,c) { yylval.intval = c; return y; } +#endif /* defined(YYDEBUG) */ + + + static char buffer[500], *bufptr = buffer; + static int eof_found = 0; + int c; + + if (eof_found != 0) { + eof_found++; + if (eof_found > 2) { + fprintf(stderr, "End of file ignored.\n"); + exit(1); + } + Return(EOF,0); + } + while ((c = Getchar()) != EOF) { + switch (c) { + case '#': + ret_token(c); + while (((c = Getchar()) != EOF) && (c != '\n')) { + ; + } + save(c); + break; + case '<': + case '?': + ret_token(c); + Return(MACRO_CHAR, c); + case '\t': + case ' ': + ret_token(c); + Return(WHITE_SPACE, c); + case '-': + case '@': + case ':': + case ';': + case '=': + case '$': + case '{': + case '}': + case '(': + case ')': + ret_token(c); + Return(c,c); + case '\'': + case '"': + if (bufptr != buffer) { + if (bufptr[-1] == '\\') { + bufptr[-1] = c; + } + break; + } else { + int newc; + + ret_token(c); + *bufptr++ = c; + while (((newc = Getchar()) != EOF) && (newc != c)) { + *bufptr++ = newc; + } + *bufptr++ = c; + *bufptr = 0; + bufptr = buffer; + yylval.string = string_lookup(buffer); + return QUOTED_STRING; + } + case '\n': + if (bufptr != buffer) { + if (bufptr[-1] == '\\') { + bufptr--; + if ((c = Getchar()) != '\t') { + yyerror("continuation line doesn't begin with a tab"); + save(c); + } + ret_token(c); + Return(WHITE_SPACE, c); + } + } + ret_token(c); + Return(NL, 0); + default: + *bufptr++ = c; + break; + } + } + + eof_found = 1; + + ret_token(' '); + Return(EOF, 0); +} + +main() +{ +#define YYDEBUG + extern int yydebug; + + null = same_item(string_lookup("")); + newline = same_item(string_lookup("\n")); + blank = same_item(string_lookup(" ")); + cwd_line = same_cat(same_copy(newline), + same_cat(same_item(string_lookup("cd ${CWD}")), + same_copy(newline))); + + yyparse(); + + do_dump(); + + return 0; +} + +#if defined(YYDEBUG) +dump_same(same) +same_t *same; +{ + same_t *same2; + + for (visit(same, same2); !visited(same2); visit_next(same2)) { + printf(same2->string->string); + } + visit_end(); +} +#endif /* YYDEBUG */ + +do_dump() +{ + string_t *string; + same_t *same, *same2; + + if (yydebug > 1) { + printf("strings...\n"); + for (string = strings; string; string = string->next) { + printf("\t%s\n", string->string); + } + } + + printf("# variables...\n"); + for (visit(variables, same); !visited(same); visit_next(same)) { + printf("%s =\t", same->string->string); + for (visit(same->value_list, same2); !visited(same2); + visit_next(same2)) { + printf(same2->string->string); + } + visit_end(); + printf("\n"); + } + visit_end(); + + printf("\n\n#targets...\n"); + for (visit(targets, same); !visited(same); visit_next(same)) { + printf("\n%s:\t", same->string->string); + for (visit(same->depend_list, same2); !visited(same2); + visit_next(same2)) { + printf(same2->string->string); + } + visit_end(); + printf("\n\t"); + for (visit(same->action_list, same2); !visited(same2); + visit_next(same2)) { + printf(same2->string->string); + if (same2->string->string[0] == '\n') { + printf("\t"); + } + } + visit_end(); + printf("\n"); + } + visit_end(); +} diff --git a/usr.bin/tn3270/tools/prt3270.c b/usr.bin/tn3270/tools/prt3270.c new file mode 100644 index 0000000..55d72d5 --- /dev/null +++ b/usr.bin/tn3270/tools/prt3270.c @@ -0,0 +1,620 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)prt3270.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#if defined(unix) +#endif +#include +#include + +#include "../general/general.h" + +#include "../api/asc_ebc.h" +#include "../ctlr/hostctlr.h" +#include "../ctlr/screen.h" +#include "../ctlr/function.h" +#include "../api/astosc.h" +#include "../general/globals.h" + +#include "../ctlr/kbd.out" + + +int NumberColumns = 80; + +int direction; + +int column = 1; +int indenting = 0; +int direction = '?'; + +unsigned char printBuffer[200], *print = printBuffer; + +#define ColsLeft() (79-column) /* A little room for error */ + + +void +putSpace() +{ + extern void Column1(); + unsigned char *ourPrint = print; + + print = printBuffer; /* For mutual calls */ + *ourPrint = 0; + if (ColsLeft() < 0) { + Column1(); + } + if (column != (indenting*8+1)) { + putchar(' '); + } else { + int i; + + putchar(direction); + putchar(' '); + for (i = 0; i < indenting; i++) { + putchar('\t'); + } + } + printf("%s", printBuffer); + column += strlen(printBuffer); +} + +void +Column1() +{ + if (print != printBuffer) { + putSpace(); + } + if (column != (indenting*8+1)) { + putchar('\n'); + column = indenting*8+1; + } +} + +void +Indent() +{ + if ((column != (indenting*8+1)) || (print != printBuffer)) { + Column1(); + } + indenting++; + column = indenting*8+1; +} + +void +Undent() +{ + if ((column != (indenting*8+1)) || (print != printBuffer)) { + Column1(); + } + indenting--; + if (indenting < 0) { + fflush(stdout); + fprintf(stderr, "INTERNAL ERROR: indenting < 0.\n"); + fflush(stderr); + } else { + column = indenting*8+1; + } +} + +void +putChar(character) +int character; +{ + *print++ = character; + column++; +} + +void +putstr(s) +char *s; +{ + while (*s) { + putChar(*s++); + } +} + +void +put2hex(i) +int i; +{ + char place[40]; + + sprintf(place, "%02x", i); + putstr(place); +} + + +void +putdecimal(i) +int i; +{ + char place[40]; + + sprintf(place, "%d", i); + putstr(place); +} + +void +puthex(i) +int i; +{ + char place[40]; + + sprintf(place, "%x", i); + putstr(place); +} + +void +putEChar(character) +int character; +{ + putChar(ebc_asc[character]); + if (ColsLeft() < 10) { + Column1(); + } +} + +void +PrintAid(i) +int i; +{ + struct astosc *this; + + for (this = &astosc[0]; this <= &astosc[highestof(astosc)]; this++) { + if (this->function == FCN_AID) { + int j; + + switch (this->shiftstate) { + case 0: + j = 0; + break; + case SHIFT_UPSHIFT: + j = 1; + break; + case SHIFT_ALT: + j = 2; + break; + case (SHIFT_UPSHIFT|SHIFT_ALT): + j = 3; + break; + default: + fprintf(stderr, "Bad shiftstate 0x%x.\n", this->shiftstate); + exit(1); + } + if (hits[this->scancode].hit[j].code == i) { + putstr(this->name); + return; + } + } + } + + putstr("Unknown AID 0x"); + put2hex(i); +} + +void +PrintAddr(i) +int i; +{ + if (ColsLeft() < 9) { + Column1(); + } + putChar('('); + putdecimal(ScreenLine(i)); + putChar(','); + putdecimal(ScreenLineOffset(i)); + putChar(')'); +} + + +/* returns the number of characters consumed */ +int +DataFromNetwork(buffer, count, control) +register unsigned char *buffer; /* what the data is */ +register int count; /* and how much there is */ +int control; /* this buffer ended block? */ +{ + int origCount; + register int c; + register int i; + static int Command; + static int Wcc; + static int LastWasTerminated = 1; /* was "control" = 1 last time? */ + + if (count == 0) { + Column1(); + return 0; + } + + origCount = count; + + if (LastWasTerminated) { + + if (count < 2) { + if (count == 0) { + fflush(stdout); + fprintf(stderr, "Short count received from host!\n"); + fflush(stderr); + return(count); + } + Command = buffer[0]; + switch (Command) { /* This had better be a read command */ + case CMD_READ_MODIFIED: + putstr("read_modified command\n"); + break; + case CMD_SNA_READ_MODIFIED: + putstr("sna_read_modified command\n"); + break; + case CMD_SNA_READ_MODIFIED_ALL: + putstr("sna_read_modified_all command\n"); + break; + case CMD_READ_BUFFER: + putstr("read_buffer command\n"); + break; + case CMD_SNA_READ_BUFFER: + putstr("sna_read_buffer command\n"); + break; + default: + break; + } + return(1); /* We consumed everything */ + } + Command = buffer[0]; + Wcc = buffer[1]; + switch (Command) { + case CMD_ERASE_WRITE: + putstr("erase write command "); + break; + case CMD_ERASE_WRITE_ALTERNATE: + putstr("erase write alternate command "); + break; + case CMD_SNA_ERASE_WRITE: + putstr("sna erase write command "); + break; + case CMD_SNA_ERASE_WRITE_ALTERNATE: + putstr("erase write alternate command "); + break; + case CMD_ERASE_ALL_UNPROTECTED: + putstr("erase all unprotected command "); + break; + case CMD_SNA_ERASE_ALL_UNPROTECTED: + putstr("sna erase write command "); + break; + case CMD_WRITE: + putstr("write command "); + break; + case CMD_SNA_WRITE: + putstr("sna write command "); + break; + default: + putstr("Unexpected command code 0x"); + puthex(Command); + putstr(" received."); + Column1(); + break; + } + putstr("WCC is 0x"); + puthex(Wcc); + Column1(); + + count -= 2; /* strip off command and wcc */ + buffer += 2; + + } + LastWasTerminated = 0; /* then, reset at end... */ + + while (count) { + count--; + c = *buffer++; + if (IsOrder(c)) { + /* handle an order */ + switch (c) { +# define Ensure(x) if (count < x) { \ + if (!control) { \ + return(origCount-(count+1)); \ + } else { \ + /* XXX - should not occur */ \ + count = 0; \ + break; \ + } \ + } + case ORDER_SF: + Ensure(1); + c = *buffer++; + count--; + putstr("SF (0x"); + put2hex(c); + putstr(") "); + break; + case ORDER_SBA: + Ensure(2); + i = buffer[0]; + c = buffer[1]; + buffer += 2; + count -= 2; + putstr("SBA to "); + PrintAddr(Addr3270(i,c)); + putSpace(); + break; + case ORDER_IC: + putstr("IC"); + putSpace(); + break; + case ORDER_PT: + putstr("PT"); + putSpace(); + break; + case ORDER_RA: + Ensure(3); + i = Addr3270(buffer[0], buffer[1]); + c = buffer[2]; + buffer += 3; + count -= 3; + putstr("RA to "); + PrintAddr(i); + putstr(" of 0x"); + put2hex(c); + putSpace(); + break; + case ORDER_EUA: /* (from [here,there), ie: half open interval] */ + Ensure(2); + putstr("EUA to "); + PrintAddr(Addr3270(buffer[0], buffer[1])); + putSpace(); + buffer += 2; + count -= 2; + break; + case ORDER_YALE: /* special YALE defined order */ + Ensure(2); /* need at least two characters */ + putstr("YALE order"); + putSpace(); + break; + default: + putstr("UNKNOWN ORDER: 0x"); + put2hex(c); + putSpace(); + break; + } + if (count < 0) { + count = 0; + } + } else { + /* Data comes in large clumps - take it all */ + putstr("DATA:"); + Indent(); + putEChar(c); + c = *buffer; + while (count && !IsOrder(c)) { + putEChar(c); + count--; + buffer++; + c = *buffer; + } + Undent(); + } + } + LastWasTerminated = control; + return origCount - count; +} + +int +DataToNetwork(buffer, count, control) +unsigned char *buffer; +int count; +int control; +{ +#define NEED_AID 0 +#define JUST_GOT_AID 1 +#define DATA 2 +#define DATA_CONTINUE 3 + static int state = NEED_AID; + static int aid; + int origCount = count; + + if (count == 0) { + if (control) { + state = NEED_AID; + } + Column1(); + return 0; + } + + switch (state) { + case NEED_AID: + aid = buffer[0]; + buffer++; + count--; + PrintAid(aid); + putSpace(); + if (aid == AID_TREQ) { + state = DATA; + } else { + state = JUST_GOT_AID; + } + return origCount - count + DataToNetwork(buffer, count, control); + case JUST_GOT_AID: + Ensure(2); + PrintAddr(Addr3270(buffer[0], buffer[1])); + putSpace(); + buffer += 2; + count -= 2; + state = DATA; + return origCount - count + DataToNetwork(buffer, count, control); + case DATA: + case DATA_CONTINUE: + while (count) { + if (*buffer == ORDER_SBA) { + if (state == DATA_CONTINUE) { + Undent(); + state = DATA; + } + putstr("SBA "); + PrintAddr(Addr3270(buffer[1], buffer[2])); + putSpace(); + buffer += 3; + count -= 3; + } else { + if (state == DATA) { + putstr("DATA:"); + Indent(); + state = DATA_CONTINUE; + } + putEChar(*buffer); + buffer++; + count--; + } + } + if (control) { + if (state == DATA_CONTINUE) { + Undent(); + } + state = NEED_AID; + } + return origCount-count; + } +} + +int +GetXValue(c) +int c; +{ + if (!isascii(c)) { + fflush(stdout); + fprintf(stderr, "Non-hex digit 0x%x.\n"); + fflush(stderr); + return 0; + } else { + if (islower(c)) { + return (c-'a')+10; + } else if (isupper(c)) { + return (c-'A')+10; + } else { + return c-'0'; + } + } +} + +unsigned char outbound[8192], inbound[8192], + *outnext = outbound, *innext = inbound, *p = 0; + +void +termblock(old, new, control) +int old, + new; /* old and new directions */ +{ + int count; + + if (p) { + if (old == '<') { + outnext = p; + count = DataFromNetwork(outbound, outnext-outbound, control); + if (outbound+count == outnext) { + outnext = outbound; + } else { + memcpy(outbound, outbound+count, outnext-(outbound+count)); + outnext = outbound+count; + } + } else { + innext = p; + count = DataToNetwork(inbound, innext-inbound, control); + if (inbound+count == innext) { + innext = inbound; + } else { + memcpy(inbound, inbound+count, innext-(inbound+count)); + innext = inbound+count; + } + } + } + if (new == '<') { + p = outnext; + } else if (new == '>') { + p = innext; + } else { + fprintf(stderr, "Bad direction character '%c'.\n", new); + exit(1); + } +} + +main() +{ + int location; + char new; + int c, c1; + + memset(Orders, 0, sizeof Orders); + Orders[ORDER_SF] = Orders[ORDER_SBA] = Orders[ORDER_IC] + = Orders[ORDER_PT] = Orders[ORDER_RA] = Orders[ORDER_EUA] + = Orders[ORDER_YALE] = 1; + + while (scanf("%c 0x%x\t", &new, &location) != EOF) { + if (new != direction) { + termblock(direction, new, 0); + direction = new; + } + while (((c = getchar()) != EOF) && (c != '\n') && (isxdigit(c))) { +#define NORMAL 0 +#define GOT0XFF 0xff + static int state = NORMAL; + + c1 = getchar(); + c = (GetXValue(c) << 4) + GetXValue(c1); + switch (state) { + case NORMAL: + if (c == 0xff) { + state = GOT0XFF; + } else { + *p++ = c; + } + break; + case GOT0XFF: + if (c == 0xef) { + termblock(direction, direction, 1); + } else { + *p++ = 0xff; + *p++ = c; + } + state = NORMAL; + } + } + } + return 0; +} diff --git a/usr.bin/touch/Makefile b/usr.bin/touch/Makefile new file mode 100644 index 0000000..5c153b3 --- /dev/null +++ b/usr.bin/touch/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= touch + +.include diff --git a/usr.bin/touch/touch.1 b/usr.bin/touch/touch.1 new file mode 100644 index 0000000..c6eeaa3 --- /dev/null +++ b/usr.bin/touch/touch.1 @@ -0,0 +1,167 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)touch.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt TOUCH 1 +.Os +.Sh NAME +.Nm touch +.Nd change file access and modification times +.Sh SYNOPSIS +.Nm touch +.Op Fl acfm +.Op Fl r Ar file +.Op Fl t [[CC]YY]MMDDhhmm[.SS] +.Ar file ... +.Sh DESCRIPTION +The +.Nm touch +utility sets the modification and access times of files to the +current time of day. +If the file doesn't exist, it is created with default permissions. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl a +Change the access time of the file. +The modification time of the file is not changed unless the +.Fl m +flag is also specified. +.It Fl c +Do not create the file if it does not exist. +The +.Nm touch +utility does not treat this as an error. +No error messages are displayed and the exit value is not affected. +.It Fl f +Attempt to force the update, even if the file permissions do not +currently permit it. +.It Fl m +Change the modification time of the file. +The access time of the file is not changed unless the +.Fl a +flag is also specified. +.It Fl r +Use the access and modifications times from the specified file +instead of the current time of day. +.It Fl t +Change the access and modification times to the specified time. +The argument should be in the form +.Dq [[CC]YY]MMDDhhmm[.SS] +where each pair of letters represents the following: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Ar CC +The first two digits of the year (the century). +.It Ar YY +The second two digits of the year. +If +.Dq YY +is specified, but +.Dq CC +is not, a value for +.Dq YY +between 69 and 99 results in a +.Dq YY +value of 19. +Otherwise, a +.Dq YY +value of 20 is used. +.It Ar MM +The month of the year, from 1 to 12. +.It Ar DD +the day of the month, from 1 to 31. +.It Ar hh +The hour of the day, from 0 to 23. +.It Ar mm +The minute of the hour, from 0 to 59. +.It Ar SS +The second of the minute, from 0 to 61. +.El +.Pp +If the +.Dq CC +and +.Dq YY +letter pairs are not specified, the values default to the current +year. +If the +.Dq SS +letter pair is not specified, the value defaults to 0. +.El +.Pp +The +.Nm touch +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr utimes 2 +.Sh COMPATIBILITY +The obsolescent form of +.Nm touch , +where a time format is specified as the first argument, is supported. +When no +.Fl r +or +.Fl t +option is specified, there are at least two arguments, and the first +argument is a string of digits either eight or ten characters in length, +the first argument is interpreted as a time specification of the form +.Dq MMDDhhmm[YY] . +.Pp +The +.Dq MM , +.Dq DD , +.Dq hh +and +.Dq mm +letter pairs are treated as their counterparts specified to the +.Fl t +option. +If the +.Dq YY +letter pair is in the range 69 to 99, the year is set to 1969 to 1999, +otherwise, the year is set in the 21st century. +.Sh HISTORY +A +.Nm touch +command appeared in +.At v7 . +.Sh STANDARDS +The +.Nm touch +function is expected to be a superset of the +.St -p1003.2 +specification. diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c new file mode 100644 index 0000000..46efb64 --- /dev/null +++ b/usr.bin/touch/touch.c @@ -0,0 +1,342 @@ +/* + * 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 copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +int rw __P((char *, struct stat *, int)); +void stime_arg1 __P((char *, struct timeval *)); +void stime_arg2 __P((char *, int, struct timeval *)); +void stime_file __P((char *, struct timeval *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat sb; + struct timeval tv[2]; + int aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset; + char *p; + + aflag = cflag = fflag = mflag = timeset = 0; + if (gettimeofday(&tv[0], NULL)) + err(1, "gettimeofday"); + + while ((ch = getopt(argc, argv, "acfmr:t:")) != EOF) + switch(ch) { + case 'a': + aflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'f': + fflag = 1; + break; + case 'm': + mflag = 1; + break; + case 'r': + timeset = 1; + stime_file(optarg, tv); + break; + case 't': + timeset = 1; + stime_arg1(optarg, tv); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* Default is both -a and -m. */ + if (aflag == 0 && mflag == 0) + aflag = mflag = 1; + + /* + * If no -r or -t flag, at least two operands, the first of which + * is an 8 or 10 digit number, use the obsolete time specification. + */ + if (!timeset && argc > 1) { + (void)strtol(argv[0], &p, 10); + len = p - argv[0]; + if (*p == '\0' && (len == 8 || len == 10)) { + timeset = 1; + stime_arg2(*argv++, len == 10, tv); + } + } + + /* Otherwise use the current time of day. */ + if (!timeset) + tv[1] = tv[0]; + + if (*argv == NULL) + usage(); + + for (rval = 0; *argv; ++argv) { + /* See if the file exists. */ + if (stat(*argv, &sb)) + if (!cflag) { + /* Create the file. */ + fd = open(*argv, + O_WRONLY | O_CREAT, DEFFILEMODE); + if (fd == -1 || fstat(fd, &sb) || close(fd)) { + rval = 1; + warn("%s", *argv); + continue; + } + + /* If using the current time, we're done. */ + if (!timeset) + continue; + } else + continue; + + if (!aflag) + TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); + if (!mflag) + TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); + + /* Try utimes(2). */ + if (!utimes(*argv, tv)) + continue; + + /* If the user specified a time, nothing else we can do. */ + if (timeset) { + rval = 1; + warn("%s", *argv); + } + + /* + * System V and POSIX 1003.1 require that a NULL argument + * set the access/modification times to the current time. + * The permission checks are different, too, in that the + * ability to write the file is sufficient. Take a shot. + */ + if (!utimes(*argv, NULL)) + continue; + + /* Try reading/writing. */ + if (rw(*argv, &sb, fflag)) + rval = 1; + } + exit(rval); +} + +#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; + +void +stime_arg1(arg, tvp) + char *arg; + struct timeval *tvp; +{ + struct tm *t; + int yearset; + char *p; + /* Start with the current time. */ + if ((t = localtime(&tvp[0].tv_sec)) == NULL) + err(1, "localtime"); + /* [[CC]YY]MMDDhhmm[.SS] */ + if ((p = strchr(arg, '.')) == NULL) + t->tm_sec = 0; /* Seconds defaults to 0. */ + else { + if (strlen(p + 1) != 2) + goto terr; + *p++ = '\0'; + t->tm_sec = ATOI2(p); + } + + yearset = 0; + switch(strlen(arg)) { + case 12: /* CCYYMMDDhhmm */ + t->tm_year = ATOI2(arg); + t->tm_year *= 1000; + yearset = 1; + /* FALLTHOUGH */ + case 10: /* YYMMDDhhmm */ + if (yearset) { + yearset = ATOI2(arg); + t->tm_year += yearset; + } else { + yearset = ATOI2(arg); + if (yearset < 69) + t->tm_year = yearset + 2000; + else + t->tm_year = yearset + 1900; + } + t->tm_year -= 1900; /* Convert to UNIX time. */ + /* FALLTHROUGH */ + case 8: /* MMDDhhmm */ + t->tm_mon = ATOI2(arg); + --t->tm_mon; /* Convert from 01-12 to 00-11 */ + t->tm_mday = ATOI2(arg); + t->tm_hour = ATOI2(arg); + t->tm_min = ATOI2(arg); + break; + default: + goto terr; + } + + t->tm_isdst = -1; /* Figure out DST. */ + tvp[0].tv_sec = tvp[1].tv_sec = mktime(t); + if (tvp[0].tv_sec == -1) +terr: errx(1, + "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); + + tvp[0].tv_usec = tvp[1].tv_usec = 0; +} + +void +stime_arg2(arg, year, tvp) + char *arg; + int year; + struct timeval *tvp; +{ + struct tm *t; + /* Start with the current time. */ + if ((t = localtime(&tvp[0].tv_sec)) == NULL) + err(1, "localtime"); + + t->tm_mon = ATOI2(arg); /* MMDDhhmm[yy] */ + --t->tm_mon; /* Convert from 01-12 to 00-11 */ + t->tm_mday = ATOI2(arg); + t->tm_hour = ATOI2(arg); + t->tm_min = ATOI2(arg); + if (year) + t->tm_year = ATOI2(arg); + + t->tm_isdst = -1; /* Figure out DST. */ + tvp[0].tv_sec = tvp[1].tv_sec = mktime(t); + if (tvp[0].tv_sec == -1) + errx(1, + "out of range or illegal time specification: MMDDhhmm[yy]"); + + tvp[0].tv_usec = tvp[1].tv_usec = 0; +} + +void +stime_file(fname, tvp) + char *fname; + struct timeval *tvp; +{ + struct stat sb; + + if (stat(fname, &sb)) + err(1, "%s", fname); + TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec); + TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec); +} + +int +rw(fname, sbp, force) + char *fname; + struct stat *sbp; + int force; +{ + int fd, needed_chmod, rval; + u_char byte; + + /* Try regular files and directories. */ + if (!S_ISREG(sbp->st_mode) && !S_ISDIR(sbp->st_mode)) { + warnx("%s: %s", fname, strerror(EFTYPE)); + return (1); + } + + needed_chmod = rval = 0; + if ((fd = open(fname, O_RDWR, 0)) == -1) { + if (!force || chmod(fname, DEFFILEMODE)) + goto err; + if ((fd = open(fname, O_RDWR, 0)) == -1) + goto err; + needed_chmod = 1; + } + + if (sbp->st_size != 0) { + if (read(fd, &byte, sizeof(byte)) != sizeof(byte)) + goto err; + if (lseek(fd, (off_t)0, SEEK_SET) == -1) + goto err; + if (write(fd, &byte, sizeof(byte)) != sizeof(byte)) + goto err; + } else { + if (write(fd, &byte, sizeof(byte)) != sizeof(byte)) { +err: rval = 1; + warn("%s", fname); + } else if (ftruncate(fd, (off_t)0)) { + rval = 1; + warn("%s: file modified", fname); + } + } + + if (close(fd) && rval != 1) { + rval = 1; + warn("%s", fname); + } + if (needed_chmod && chmod(fname, sbp->st_mode) && rval != 1) { + rval = 1; + warn("%s: permissions modified", fname); + } + return (rval); +} + +__dead void +usage() +{ + (void)fprintf(stderr, + "usage: touch [-acfm] [-r file] [-t time] file ...\n"); + exit(1); +} diff --git a/usr.bin/tput/Makefile b/usr.bin/tput/Makefile new file mode 100644 index 0000000..abec983 --- /dev/null +++ b/usr.bin/tput/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tput +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap +MLINKS= tput.1 clear.1 + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/clear.sh ${DESTDIR}/usr/bin/clear + +.include diff --git a/usr.bin/tput/clear.sh b/usr.bin/tput/clear.sh new file mode 100644 index 0000000..add589b --- /dev/null +++ b/usr.bin/tput/clear.sh @@ -0,0 +1,37 @@ +#!/bin/sh - +# +# Copyright (c) 1989, 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. +# +# @(#)clear.sh 8.1 (Berkeley) 6/6/93 +# + +exec tput clear diff --git a/usr.bin/tput/tput.1 b/usr.bin/tput/tput.1 new file mode 100644 index 0000000..9a348431 --- /dev/null +++ b/usr.bin/tput/tput.1 @@ -0,0 +1,117 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tput.1 8.2 (Berkeley) 3/19/94 +.\" +.Dd March 19, 1994 +.Dt TPUT 1 +.Os BSD 4.4 +.Sh NAME +.Nm tput +.Nd terminal capability interface +.Sh SYNOPSIS +.Nm tput +.Op Fl T Ar term +.Ar attribute +.Sh DESCRIPTION +.Nm Tput +makes terminal-dependent information available to users or shell +applications. +The options are as follows: +.Bl -tag -width Ds +.It Fl T +The terminal name as specified in the +.Xr termcap +database, for example, ``vt100'' or ``xterm''. +If not specified, +.Nm tput +retrieves the +.Dq Ev TERM +variable from the environment. +.El +.Pp +.Nm Tput +outputs a string if the +.Ar attribute +is of type string; a number if it is of type integer. +Otherwise, +.Nm tput +exits 0 if the terminal has the capability and 1 if it does not, +without further action. +.Pp +If the +.Ar attribute +is of type string, and takes arguments (e.g. cursor movement, +the termcap +.Dq cm +sequence) the arguments are taken from the command line immediately +following the attribute. +.Pp +The following special attributes are available: +.Bl -tag -width Ar +.It clear +Clear the screen (the +.Xr termcap +``cl'' sequence). +.It init +Initialize the terminal (the +.Xr termcap +``is'' sequence). +.It longname +Print the descriptive name of the user's terminal type. +.It reset +Reset the terminal (the +.Xr termcap +``rs'' sequence). +.Sh DIAGNOSTICS +The exit value of +.Nm tput +is based on the last attribute specified. +If the attribute is of type string or of type integer, +.Nm tput +exits 0 if the attribute is defined for this terminal type and 1 +if it is not. +If the attribute is of type boolean, +.Nm tput +exits 0 if the terminal has this attribute, and 1 if it does not. +.Nm Tput +exits 2 if any error occurred. +.Sh SEE ALSO +.Xr termcap 3 , +.Xr termcap 5 +.Sh BUGS +.Nm Tput +can't really distinguish between different types of attributes. +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/tput/tput.c b/usr.bin/tput/tput.c new file mode 100644 index 0000000..8da0be7 --- /dev/null +++ b/usr.bin/tput/tput.c @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 1980, 1988, 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 copyright[] = +"@(#) Copyright (c) 1980, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tput.c 8.2 (Berkeley) 3/19/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include + +static void prlongname __P((char *)); +static void setospeed __P((void)); +static void outc __P((int)); +static void usage __P((void)); +static char **process __P((char *, char *, char **)); + +int +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + int ch, exitval, n; + char *cptr, *p, *term, buf[1024], tbuf[1024]; + + term = NULL; + while ((ch = getopt(argc, argv, "T:")) != EOF) + switch(ch) { + case 'T': + term = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!term && !(term = getenv("TERM"))) +errx(2, "no terminal type specified and no TERM environmental variable."); + if (tgetent(tbuf, term) != 1) + err(2, "tgetent failure"); + setospeed(); + for (exitval = 0; (p = *argv) != NULL; ++argv) { + switch (*p) { + case 'c': + if (!strcmp(p, "clear")) + p = "cl"; + break; + case 'i': + if (!strcmp(p, "init")) + p = "is"; + break; + case 'l': + if (!strcmp(p, "longname")) + prlongname(tbuf); + continue; + case 'r': + if (!strcmp(p, "reset")) + p = "rs"; + break; + } + cptr = buf; + if (tgetstr(p, &cptr)) + argv = process(p, buf, argv); + else if ((n = tgetnum(p)) != -1) + (void)printf("%d\n", n); + else + exitval = !tgetflag(p); + } + exit(exitval); +} + +static void +prlongname(buf) + char *buf; +{ + int savech; + char *p, *savep; + + for (p = buf; *p && *p != ':'; ++p); + savech = *(savep = p); + for (*p = '\0'; p >= buf && *p != '|'; --p); + (void)printf("%s\n", p + 1); + *savep = savech; +} + +static char ** +process(cap, str, argv) + char *cap, *str, **argv; +{ + static char errfew[] = + "not enough arguments (%d) for capability `%s'"; + static char errmany[] = + "too many arguments (%d) for capability `%s'"; + static char erresc[] = + "unknown %% escape `%c' for capability `%s'"; + char *cp; + int arg_need, arg_rows, arg_cols; + + /* Count how many values we need for this capability. */ + for (cp = str, arg_need = 0; *cp != '\0'; cp++) + if (*cp == '%') + switch (*++cp) { + case 'd': + case '2': + case '3': + case '.': + case '+': + arg_need++; + break; + case '%': + case '>': + case 'i': + case 'r': + case 'n': + case 'B': + case 'D': + break; + default: + /* + * hpux has lot's of them, but we complain + */ + errx(2, erresc, *cp, cap); + } + + /* And print them. */ + switch (arg_need) { + case 0: + (void)tputs(str, 1, outc); + break; + case 1: + arg_cols = 0; + + if (*++argv == NULL || *argv[0] == '\0') + errx(2, errfew, 1, cap); + arg_rows = atoi(*argv); + + (void)tputs(tgoto(str, arg_cols, arg_rows), 1, outc); + break; + case 2: + if (*++argv == NULL || *argv[0] == '\0') + errx(2, errfew, 2, cap); + arg_cols = atoi(*argv); + + if (*++argv == NULL || *argv[0] == '\0') + errx(2, errfew, 2, cap); + arg_rows = atoi(*argv); + + (void) tputs(tgoto(str, arg_cols, arg_rows), arg_rows, outc); + break; + + default: + errx(2, errmany, arg_need, cap); + } + return (argv); +} + +static void +setospeed() +{ +#undef ospeed + extern short ospeed; + struct termios t; + + if (tcgetattr(STDOUT_FILENO, &t) != -1) + ospeed = 0; + else + ospeed = cfgetospeed(&t); +} + +static void +outc(c) + int c; +{ + (void)putchar(c); +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: tput [-T term] attribute ...\n"); + exit(1); +} diff --git a/usr.bin/tr/Makefile b/usr.bin/tr/Makefile new file mode 100644 index 0000000..7124942 --- /dev/null +++ b/usr.bin/tr/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tr +SRCS= str.c tr.c + +.include diff --git a/usr.bin/tr/extern.h b/usr.bin/tr/extern.h new file mode 100644 index 0000000..9e82d06 --- /dev/null +++ b/usr.bin/tr/extern.h @@ -0,0 +1,51 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +typedef struct { + enum { STRING1, STRING2 } which; + enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE, SET } state; + int cnt; /* character count */ + int lastch; /* last character */ + int equiv[2]; /* equivalence set */ + int *set; /* set of characters */ + char *str; /* user's string */ +} STR; + +#include +#define NCHARS (UCHAR_MAX + 1) /* Number of possible characters. */ +#define OOBCH (UCHAR_MAX + 1) /* Out of band character value. */ + +void err __P((const char *fmt, ...)); +int next __P((STR *)); diff --git a/usr.bin/tr/str.c b/usr.bin/tr/str.c new file mode 100644 index 0000000..f86493a --- /dev/null +++ b/usr.bin/tr/str.c @@ -0,0 +1,342 @@ +/*- + * 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[] = "@(#)str.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "extern.h" + +static int backslash __P((STR *)); +static int bracket __P((STR *)); +static int c_class __P((const void *, const void *)); +static void genclass __P((STR *)); +static void genequiv __P((STR *)); +static int genrange __P((STR *)); +static void genseq __P((STR *)); + +int +next(s) + register STR *s; +{ + register int ch; + + switch (s->state) { + case EOS: + return (0); + case INFINITE: + return (1); + case NORMAL: + switch (ch = *s->str) { + case '\0': + s->state = EOS; + return (0); + case '\\': + s->lastch = backslash(s); + break; + case '[': + if (bracket(s)) + return (next(s)); + /* FALLTHROUGH */ + default: + ++s->str; + s->lastch = ch; + break; + } + + /* We can start a range at any time. */ + if (s->str[0] == '-' && genrange(s)) + return (next(s)); + return (1); + case RANGE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + ++s->lastch; + return (1); + case SEQUENCE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + return (1); + case SET: + if ((s->lastch = s->set[s->cnt++]) == OOBCH) { + s->state = NORMAL; + return (next(s)); + } + return (1); + } + /* NOTREACHED */ +} + +static int +bracket(s) + register STR *s; +{ + register char *p; + + switch (s->str[1]) { + case ':': /* "[:class:]" */ + if ((p = strstr(s->str + 2, ":]")) == NULL) + return (0); + *p = '\0'; + s->str += 2; + genclass(s); + s->str = p + 2; + return (1); + case '=': /* "[=equiv=]" */ + if ((p = strstr(s->str + 2, "=]")) == NULL) + return (0); + s->str += 2; + genequiv(s); + return (1); + default: /* "[\###*n]" or "[#*n]" */ + if ((p = strpbrk(s->str + 2, "*]")) == NULL) + return (0); + if (p[0] != '*' || index(p, ']') == NULL) + return (0); + s->str += 1; + genseq(s); + return (1); + } + /* NOTREACHED */ +} + +int isalnum __P((int)), + isalpha __P((int)), + isblank __P((int)), + isspace __P((int)), + iscntrl __P((int)), + isdigit __P((int)), + isgraph __P((int)), + islower __P((int)), + isprint __P((int)), + ispunct __P((int)), + isupper __P((int)), + isxdigit __P((int)); + +typedef struct { + char *name; + int (*func) __P((int)); + int *set; +} CLASS; + +static CLASS classes[] = { + { "alnum", isalnum, }, + { "alpha", isalpha, }, + { "blank", isblank, }, + { "cntrl", iscntrl, }, + { "digit", isdigit, }, + { "graph", isgraph, }, + { "lower", islower, }, + { "print", isupper, }, + { "punct", ispunct, }, + { "space", isspace, }, + { "upper", isupper, }, + { "xdigit", isxdigit, }, +}; + +static void +genclass(s) + STR *s; +{ + register int cnt, (*func) __P((int)); + CLASS *cp, tmp; + int *p; + + tmp.name = s->str; + if ((cp = (CLASS *)bsearch(&tmp, classes, sizeof(classes) / + sizeof(CLASS), sizeof(CLASS), c_class)) == NULL) + err("unknown class %s", s->str); + + if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL) + err("%s", strerror(errno)); + bzero(p, (NCHARS + 1) * sizeof(int)); + for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt) + if ((func)(cnt)) + *p++ = cnt; + *p = OOBCH; + + s->cnt = 0; + s->state = SET; + s->set = cp->set; +} + +static int +c_class(a, b) + const void *a, *b; +{ + return (strcmp(((CLASS *)a)->name, ((CLASS *)b)->name)); +} + +/* + * English doesn't have any equivalence classes, so for now + * we just syntax check and grab the character. + */ +static void +genequiv(s) + STR *s; +{ + if (*s->str == '\\') { + s->equiv[0] = backslash(s); + if (*s->str != '=') + err("misplaced equivalence equals sign"); + } else { + s->equiv[0] = s->str[0]; + if (s->str[1] != '=') + err("misplaced equivalence equals sign"); + } + s->str += 2; + s->cnt = 0; + s->state = SET; + s->set = s->equiv; +} + +static int +genrange(s) + STR *s; +{ + int stopval; + char *savestart; + + savestart = s->str; + stopval = *++s->str == '\\' ? backslash(s) : *s->str; + if (stopval < s->lastch) { + s->str = savestart; + return (0); + } + s->cnt = stopval - s->lastch + 1; + s->state = RANGE; + --s->lastch; + return (1); +} + +static void +genseq(s) + STR *s; +{ + char *ep; + + if (s->which == STRING1) + err("sequences only valid in string2"); + + if (*s->str == '\\') + s->lastch = backslash(s); + else + s->lastch = *s->str++; + if (*s->str != '*') + err("misplaced sequence asterisk"); + + switch (*++s->str) { + case '\\': + s->cnt = backslash(s); + break; + case ']': + s->cnt = 0; + ++s->str; + break; + default: + if (isdigit(*s->str)) { + s->cnt = strtol(s->str, &ep, 0); + if (*ep == ']') { + s->str = ep + 1; + break; + } + } + err("illegal sequence count"); + /* NOTREACHED */ + } + + s->state = s->cnt ? SEQUENCE : INFINITE; +} + +/* Use the #defines isXXX() here, DON'T use them above. */ +#include + +/* + * Translate \??? into a character. Up to 3 octal digits, if no digits either + * an escape code or a literal character. + */ +static int +backslash(s) + register STR *s; +{ + register int ch, cnt, val; + + for (cnt = val = 0;;) { + ch = *++s->str; + if (!isascii(ch) || !isdigit(ch)) + break; + val = val * 8 + ch - '0'; + if (++cnt == 3) { + ++s->str; + break; + } + } + if (cnt) + return (val); + if (ch != '\0') + ++s->str; + switch (ch) { + case 'a': /* escape characters */ + return ('\7'); + case 'b': + return ('\b'); + case 'f': + return ('\f'); + case 'n': + return ('\n'); + case 'r': + return ('\r'); + case 't': + return ('\t'); + case 'v': + return ('\13'); + case '\0': /* \" -> \ */ + s->state = EOS; + return ('\\'); + default: /* \x" -> x */ + return (ch); + } +} diff --git a/usr.bin/tr/tr.1 b/usr.bin/tr/tr.1 new file mode 100644 index 0000000..5170463 --- /dev/null +++ b/usr.bin/tr/tr.1 @@ -0,0 +1,292 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)tr.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TR 1 +.Os +.Sh NAME +.Nm tr +.Nd translate characters +.Sh SYNOPSIS +.Nm tr +.Op Fl cs +.Ar string1 string2 +.Nm tr +.Op Fl c +.Fl d +.Ar string1 +.Nm tr +.Op Fl c +.Fl s +.Ar string1 +.Nm tr +.Op Fl c +.Fl ds +.Ar string1 string2 +.Sh DESCRIPTION +The +.Nm tr +utility copies the standard input to the standard output with substitution +or deletion of selected characters. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl c +Complements the set of characters in +.Ar string1 , +that is ``-c ab'' includes every character except for ``a'' and ``b''. +.It Fl d +The +.Fl d +option causes characters to be deleted from the input. +.It Fl s +The +.Fl s +option squeezes multiple occurrences of the characters listed in the last +operand (either +.Ar string1 +or +.Ar string2 ) +in the input into a single instance of the character. +This occurs after all deletion and translation is completed. +.El +.Pp +In the first synopsis form, the characters in +.Ar string1 +are translated into the characters in +.Ar string2 +where the first character in +.Ar string1 +is translated into the first character in +.Ar string2 +and so on. +If +.Ar string1 +is longer than +.Ar string2 , +the last character found in +.Ar string2 +is duplicated until +.Ar string1 +is exhausted. +.Pp +In the second synopsis form, the characters in +.Ar string1 +are deleted from the input. +.Pp +In the third synopsis form, the characters in +.Ar string1 +are compressed as described for the +.Fl s +option. +.Pp +In the fourth synopsis form, the characters in +.Ar string1 +are deleted from the input, and the characters in +.Ar string2 +are compressed as described for the +.Fl s +option. +.Pp +The following conventions can be used in +.Ar string1 +and +.Ar string2 +to specify sets of characters: +.Bl -tag -width [:equiv:] +.It character +Any character not described by one of the following conventions +represents itself. +.It \eoctal +A backslash followed by 1, 2 or 3 octal digits represents a character +with that encoded value. +To follow an octal sequence with a digit as a character, left zero-pad +the octal sequence to the full 3 octal digits. +.It \echaracter +A backslash followed by certain special characters maps to special +values. +.sp +.Bl -column +.It \ea +.It \eb +.It \ef +.It \en +.It \er +.It \et +.It \ev +.El +.sp +A backslash followed by any other character maps to that character. +.It c-c +Represents the range of characters between the range endpoints, inclusively. +.It [:class:] +Represents all characters belonging to the defined character class. +Class names are: +.sp +.Bl -column +.It alnum +.It alpha +.It cntrl +.It digit +.It graph +.It lower +.It print +.It punct +.It space +.It upper +.It xdigit +.El +.Pp +\." All classes may be used in +\." .Ar string1 , +\." and in +\." .Ar string2 +\." when both the +\." .Fl d +\." and +\." .Fl s +\." options are specified. +\." Otherwise, only the classes ``upper'' and ``lower'' may be used in +\." .Ar string2 +\." and then only when the corresponding class (``upper'' for ``lower'' +\." and vice-versa) is specified in the same relative position in +\." .Ar string1 . +\." .Pp +With the exception of the ``upper'' and ``lower'' classes, characters +in the classes are in unspecified order. +In the ``upper'' and ``lower'' classes, characters are entered in +ascending order. +.Pp +For specific information as to which ASCII characters are included +in these classes, see +.Xr ctype 3 +and related manual pages. +.It [=equiv=] +Represents all characters or collating (sorting) elements belonging to +the same equivalence class as +.Ar equiv . +If +there is a secondary ordering within the equivalence class, the characters +are ordered in ascending sequence. +Otherwise, they are ordered after their encoded values. +An example of an equivalence class might be ``c'' and ``ch'' in Spanish; +English has no equivalence classes. +.It [#*n] +Represents +.Ar n +repeated occurrences of the character represented by +.Ar # . +This +expression is only valid when it occurs in +.Ar string2 . +If +.Ar n +is omitted or is zero, it is be interpreted as large enough to extend +.Ar string2 +sequence to the length of +.Ar string1 . +If +.Ar n +has a leading zero, it is interpreted as an octal value, otherwise, +it's interpreted as a decimal value. +.El +.Pp +The +.Nm tr +utility exits 0 on success, and >0 if an error occurs. +.Sh EXAMPLES +The following examples are shown as given to the shell: +.sp +Create a list of the words in file1, one per line, where a word is taken to +be a maximal string of letters. +.sp +.D1 Li "tr -cs \*q[:alpha:]\*q \*q\en\*q < file1" +.sp +Translate the contents of file1 to upper-case. +.sp +.D1 Li "tr \*q[:lower:]\*q \*q[:upper:]\*q < file1" +.sp +Strip out non-printable characters from file1. +.sp +.D1 Li "tr -cd \*q[:print:]\*q < file1" +.Sh COMPATIBILITY +System V has historically implemented character ranges using the syntax +``[c-c]'' instead of the ``c-c'' used by historic BSD implementations and +standardized by POSIX. +System V shell scripts should work under this implementation as long as +the range is intended to map in another range, i.e. the command +``tr [a-z] [A-Z]'' will work as it will map the ``['' character in +.Ar string1 +to the ``['' character in +.Ar string2. +However, if the shell script is deleting or squeezing characters as in +the command ``tr -d [a-z]'', the characters ``['' and ``]'' will be +included in the deletion or compression list which would not have happened +under an historic System V implementation. +Additionally, any scripts that depended on the sequence ``a-z'' to +represent the three characters ``a'', ``-'' and ``z'' will have to be +rewritten as ``a\e-z''. +.Pp +The +.Nm tr +utility has historically not permitted the manipulation of NUL bytes in +its input and, additionally, stripped NUL's from its input stream. +This implementation has removed this behavior as a bug. +.Pp +The +.Nm tr +utility has historically been extremely forgiving of syntax errors, +for example, the +.Fl c +and +.Fl s +options were ignored unless two strings were specified. +This implementation will not permit illegal syntax. +.Sh STANDARDS +The +.Nm tr +utility is expected to be +.St -p1003.2 +compatible. +It should be noted that the feature wherein the last character of +.Ar string2 +is duplicated if +.Ar string2 +has less characters than +.Ar string1 +is permitted by POSIX but is not required. +Shell scripts attempting to be portable to other POSIX systems should use +the ``[#*]'' convention instead of relying on this behavior. diff --git a/usr.bin/tr/tr.c b/usr.bin/tr/tr.c new file mode 100644 index 0000000..d92a519 --- /dev/null +++ b/usr.bin/tr/tr.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "extern.h" + +static int string1[NCHARS] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */ + 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, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}, string2[NCHARS]; + +STR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL }; +STR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL }; + +static void setup __P((int *, char *, STR *, int)); +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char **argv; +{ + register int ch, cnt, lastch, *p; + int cflag, dflag, sflag, isstring2; + + cflag = dflag = sflag = 0; + while ((ch = getopt(argc, argv, "cds")) != EOF) + switch((char)ch) { + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 's': + sflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + default: + usage(); + /* NOTREACHED */ + case 1: + isstring2 = 0; + break; + case 2: + isstring2 = 1; + break; + } + + /* + * tr -ds [-c] string1 string2 + * Delete all characters (or complemented characters) in string1. + * Squeeze all characters in string2. + */ + if (dflag && sflag) { + if (!isstring2) + usage(); + + setup(string1, argv[0], &s1, cflag); + setup(string2, argv[1], &s2, 0); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] && (!string2[ch] || lastch != ch)) { + lastch = ch; + (void)putchar(ch); + } + exit(0); + } + + /* + * tr -d [-c] string1 + * Delete all characters (or complemented characters) in string1. + */ + if (dflag) { + if (isstring2) + usage(); + + setup(string1, argv[0], &s1, cflag); + + while ((ch = getchar()) != EOF) + if (!string1[ch]) + (void)putchar(ch); + exit(0); + } + + /* + * tr -s [-c] string1 + * Squeeze all characters (or complemented characters) in string1. + */ + if (sflag && !isstring2) { + setup(string1, argv[0], &s1, cflag); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] || lastch != ch) { + lastch = ch; + (void)putchar(ch); + } + exit(0); + } + + /* + * tr [-cs] string1 string2 + * Replace all characters (or complemented characters) in string1 with + * the character in the same position in string2. If the -s option is + * specified, squeeze all the characters in string2. + */ + if (!isstring2) + usage(); + + s1.str = argv[0]; + s2.str = argv[1]; + + if (cflag) + for (cnt = NCHARS, p = string1; cnt--;) + *p++ = OOBCH; + + if (!next(&s2)) + err("empty string2"); + + /* If string2 runs out of characters, use the last one specified. */ + if (sflag) + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + string2[ch] = 1; + (void)next(&s2); + } + else + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + (void)next(&s2); + } + + if (cflag) + for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt) + *p = *p == OOBCH ? ch : cnt; + + if (sflag) + for (lastch = OOBCH; (ch = getchar()) != EOF;) { + ch = string1[ch]; + if (!string2[ch] || lastch != ch) { + lastch = ch; + (void)putchar(ch); + } + } + else + while ((ch = getchar()) != EOF) + (void)putchar(string1[ch]); + exit (0); +} + +static void +setup(string, arg, str, cflag) + int *string; + char *arg; + STR *str; + int cflag; +{ + register int cnt, *p; + + str->str = arg; + bzero(string, NCHARS * sizeof(int)); + while (next(str)) + string[str->lastch] = 1; + if (cflag) + for (p = string, cnt = NCHARS; cnt--; ++p) + *p = !*p; +} + +static void +usage() +{ + (void)fprintf(stderr, "usage: tr [-cs] string1 string2\n"); + (void)fprintf(stderr, " tr [-c] -d string1\n"); + (void)fprintf(stderr, " tr [-c] -s string1\n"); + (void)fprintf(stderr, " tr [-c] -ds string1 string2\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "tr: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/true/Makefile b/usr.bin/true/Makefile new file mode 100644 index 0000000..3bebb2d --- /dev/null +++ b/usr.bin/true/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= true + +.include diff --git a/usr.bin/true/true.1 b/usr.bin/true/true.1 new file mode 100644 index 0000000..fc15a4e --- /dev/null +++ b/usr.bin/true/true.1 @@ -0,0 +1,62 @@ +.\" Copyright (c) 1983, 1985, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)true.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt TRUE 1 +.Os +.Sh NAME +.Nm true +.Nd return true value +.Sh SYNOPSIS +.Nm true +.Sh DESCRIPTION +.Nm True +is normally used in a Bourne shell script. +.Nm True +tests for the appropriate status "false" before running +(or failing to run) a list of commands. +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr false 1 +.Sh DIAGNOSTICS +The +.Nm true +utility always returns with exit code zero. +.Sh STANDARDS +The +.Nm true +function is expected to be POSIX 1003.2 compatible. diff --git a/usr.bin/true/true.c b/usr.bin/true/true.c new file mode 100644 index 0000000..0847cfa --- /dev/null +++ b/usr.bin/true/true.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)true.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +main() +{ + exit(0); +} diff --git a/usr.bin/tset/Makefile b/usr.bin/tset/Makefile new file mode 100644 index 0000000..126cf321 --- /dev/null +++ b/usr.bin/tset/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= tset +SRCS= map.c misc.c set.c term.c tset.c wrterm.c + +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap +LINKS= ${BINDIR}/tset ${BINDIR}/reset +MLINKS= tset.1 reset.1 + +.include diff --git a/usr.bin/tset/extern.h b/usr.bin/tset/extern.h new file mode 100644 index 0000000..0465a66 --- /dev/null +++ b/usr.bin/tset/extern.h @@ -0,0 +1,60 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/9/93 + */ + +/* This should be in instead. */ +extern char PC; +extern short ospeed; +int tgetent __P((char *, char *)); +int tgetflag __P((char *)); +int tgetnum __P((char *)); +char *tgetstr __P((char *, char **)); +char *tgoto __P((char *, int, int)); +int tputs __P((char *, int, void (*) __P((int)))); + +extern struct termios mode, oldmode; +extern int columns, isreset, lines; +extern int erasechar, intrchar, killchar; + +void add_mapping __P((char *, char *)); +void cat __P((char *)); +void err __P((const char *, ...)); +char *get_termcap_entry __P((char *, char **)); +char *mapped __P((char *)); +void outc __P((int)); +void reset_mode __P((void)); +void set_control_chars __P((void)); +void set_conversions __P((int)); +void set_init __P((void)); +void wrtermcap __P((char *)); diff --git a/usr.bin/tset/map.c b/usr.bin/tset/map.c new file mode 100644 index 0000000..56cb725 --- /dev/null +++ b/usr.bin/tset/map.c @@ -0,0 +1,263 @@ +/*- + * 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[] = "@(#)map.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include "extern.h" + +int baudrate __P((char *)); + +/* Baud rate conditionals for mapping. */ +#define GT 0x01 +#define EQ 0x02 +#define LT 0x04 +#define NOT 0x08 +#define GE (GT | EQ) +#define LE (LT | EQ) + +typedef struct map { + struct map *next; /* Linked list of maps. */ + char *porttype; /* Port type, or "" for any. */ + char *type; /* Terminal type to select. */ + int conditional; /* Baud rate conditionals bitmask. */ + int speed; /* Baud rate to compare against. */ +} MAP; + +MAP *cur, *maplist; + +/* + * Syntax for -m: + * [port-type][test baudrate]:terminal-type + * The baud rate tests are: >, <, @, =, ! + */ +void +add_mapping(port, arg) + char *port, *arg; +{ + MAP *mapp; + char *copy, *p, *termp; + + copy = strdup(arg); + mapp = malloc((u_int)sizeof(MAP)); + if (copy == NULL || mapp == NULL) + err("%s", strerror(errno)); + mapp->next = NULL; + if (maplist == NULL) + cur = maplist = mapp; + else { + cur->next = mapp; + cur = mapp; + } + + mapp->porttype = arg; + mapp->conditional = 0; + + arg = strpbrk(arg, "><@=!:"); + + if (arg == NULL) { /* [?]term */ + mapp->type = mapp->porttype; + mapp->porttype = NULL; + goto done; + } + + if (arg == mapp->porttype) /* [><@=! baud]:term */ + termp = mapp->porttype = NULL; + else + termp = arg; + + for (;; ++arg) /* Optional conditionals. */ + switch(*arg) { + case '<': + if (mapp->conditional & GT) + goto badmopt; + mapp->conditional |= LT; + break; + case '>': + if (mapp->conditional & LT) + goto badmopt; + mapp->conditional |= GT; + break; + case '@': + case '=': /* Not documented. */ + mapp->conditional |= EQ; + break; + case '!': + mapp->conditional |= NOT; + break; + default: + goto next; + } + +next: if (*arg == ':') { + if (mapp->conditional) + goto badmopt; + ++arg; + } else { /* Optional baudrate. */ + arg = index(p = arg, ':'); + if (arg == NULL) + goto badmopt; + *arg++ = '\0'; + mapp->speed = baudrate(p); + } + + if (*arg == NULL) /* Non-optional type. */ + goto badmopt; + + mapp->type = arg; + + /* Terminate porttype, if specified. */ + if (termp != NULL) + *termp = '\0'; + + /* If a NOT conditional, reverse the test. */ + if (mapp->conditional & NOT) + mapp->conditional = ~mapp->conditional & (EQ | GT | LT); + + /* If user specified a port with an option flag, set it. */ +done: if (port) { + if (mapp->porttype) +badmopt: err("illegal -m option format: %s", copy); + mapp->porttype = port; + } + +#ifdef MAPDEBUG + (void)printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY"); + (void)printf("type: %s\n", mapp->type); + (void)printf("conditional: "); + p = ""; + if (mapp->conditional & GT) { + (void)printf("GT"); + p = "/"; + } + if (mapp->conditional & EQ) { + (void)printf("%sEQ", p); + p = "/"; + } + if (mapp->conditional & LT) + (void)printf("%sLT", p); + (void)printf("\nspeed: %d\n", mapp->speed); +#endif +} + +/* + * Return the type of terminal to use for a port of type 'type', as specified + * by the first applicable mapping in 'map'. If no mappings apply, return + * 'type'. + */ +char * +mapped(type) + char *type; +{ + MAP *mapp; + int match; + + for (mapp = maplist; mapp; mapp = mapp->next) + if (mapp->porttype == NULL || !strcmp(mapp->porttype, type)) { + switch (mapp->conditional) { + case 0: /* No test specified. */ + match = 1; + break; + case EQ: + match = (ospeed == mapp->speed); + break; + case GE: + match = (ospeed >= mapp->speed); + break; + case GT: + match = (ospeed > mapp->speed); + break; + case LE: + match = (ospeed <= mapp->speed); + break; + case LT: + match = (ospeed < mapp->speed); + break; + } + if (match) + return (mapp->type); + } + /* No match found; return given type. */ + return (type); +} + +typedef struct speeds { + char *string; + int speed; +} SPEEDS; + +SPEEDS speeds[] = { + "0", B0, + "50", B50, + "75", B75, + "110", B110, + "134", B134, + "134.5", B134, + "150", B150, + "200", B200, + "300", B300, + "600", B600, + "1200", B1200, + "1800", B1800, + "2400", B2400, + "4800", B4800, + "9600", B9600, + "19200", B19200, + "38400", B38400, + "exta", B19200, + "extb", B38400, + NULL +}; + +int +baudrate(rate) + char *rate; +{ + SPEEDS *sp; + + /* The baudrate number can be preceded by a 'B', which is ignored. */ + if (*rate == 'B') + ++rate; + + for (sp = speeds; sp->string; ++sp) + if (!strcasecmp(rate, sp->string)) + return (sp->speed); + err("unknown baud rate %s", rate); + /* NOTREACHED */ +} diff --git a/usr.bin/tset/misc.c b/usr.bin/tset/misc.c new file mode 100644 index 0000000..c96c48c --- /dev/null +++ b/usr.bin/tset/misc.c @@ -0,0 +1,98 @@ +/*- + * 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[] = "@(#)misc.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include "extern.h" + +void +cat(file) + char *file; +{ + register int fd, nr, nw; + char buf[1024]; + + if ((fd = open(file, O_RDONLY, 0)) < 0) + err("%s: %s", file, strerror(errno)); + + while ((nr = read(fd, buf, sizeof(buf))) > 0) + if ((nw = write(STDERR_FILENO, buf, nr)) == -1) + err("write to stderr: %s", strerror(errno)); + if (nr != 0) + err("%s: %s", file, strerror(errno)); + (void)close(fd); +} + +void +outc(c) + int c; +{ + (void)putc(c, stderr); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "tset: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/tset/set.c b/usr.bin/tset/set.c new file mode 100644 index 0000000..b279a1c --- /dev/null +++ b/usr.bin/tset/set.c @@ -0,0 +1,322 @@ +/*- + * 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[] = "@(#)set.c 8.2 (Berkeley) 2/28/94"; +#endif /* not lint */ + +#include +#include +#include +#include "extern.h" + +#define CHK(val, dft) (val <= 0 ? dft : val) + +int set_tabs __P((void)); + +/* + * Reset the terminal mode bits to a sensible state. Very useful after + * a child program dies in raw mode. + */ +void +reset_mode() +{ + tcgetattr(STDERR_FILENO, &mode); + +#if defined(VDISCARD) && defined(CDISCARD) + mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD); +#endif + mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF); + mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE); +#if defined(VFLUSH) && defined(CFLUSH) + mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH); +#endif + mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR); + mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL); +#if defined(VLNEXT) && defined(CLNEXT) + mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT); +#endif + mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT); +#if defined(VREPRINT) && defined(CRPRNT) + mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT); +#endif + mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART); + mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP); + mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP); +#if defined(VWERASE) && defined(CWERASE) + mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE); +#endif + + mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR +#ifdef IUCLC + | IUCLC +#endif +#ifdef IXANY + | IXANY +#endif + | IXOFF); + + mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON +#ifdef IMAXBEL + | IMAXBEL +#endif + ); + + mode.c_oflag &= ~(0 +#ifdef OLCUC + | OLCUC +#endif +#ifdef OCRNL + | OCRNL +#endif +#ifdef ONOCR + | ONOCR +#endif +#ifdef ONLRET + | ONLRET +#endif +#ifdef OFILL + | OFILL +#endif +#ifdef OFDEL + | OFDEL +#endif +#ifdef NLDLY + | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY +#endif + ); + + mode.c_oflag |= (OPOST +#ifdef ONLCR + | ONLCR +#endif + ); + + mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); + mode.c_cflag |= (CS8 | CREAD); + mode.c_lflag &= ~(ECHONL | NOFLSH | TOSTOP +#ifdef ECHOPTR + | ECHOPRT +#endif +#ifdef XCASE + | XCASE +#endif + ); + + mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK +#ifdef ECHOCTL + | ECHOCTL +#endif +#ifdef ECHOKE + | ECHOKE +#endif + ); + + tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); +} + +/* + * Determine the erase, interrupt, and kill characters from the termcap + * entry and command line and update their values in 'mode'. + */ +void +set_control_chars() +{ + char *bp, *p, bs_char, buf[1024]; + + bp = buf; + p = tgetstr("kb", &bp); + if (p == NULL || p[1] != '\0') + p = tgetstr("bc", &bp); + if (p != NULL && p[1] == '\0') + bs_char = p[0]; + else if (tgetflag("bs")) + bs_char = CTRL('h'); + else + bs_char = 0; + + if (erasechar == 0 && !tgetflag("os") && mode.c_cc[VERASE] != CERASE) { + if (tgetflag("bs") || bs_char != 0) + erasechar = -1; + } + if (erasechar < 0) + erasechar = (bs_char != 0) ? bs_char : CTRL('h'); + + if (mode.c_cc[VERASE] == 0 || erasechar != 0) + mode.c_cc[VERASE] = erasechar ? erasechar : CERASE; + + if (mode.c_cc[VINTR] == 0 || intrchar != 0) + mode.c_cc[VINTR] = intrchar ? intrchar : CINTR; + + if (mode.c_cc[VKILL] == 0 || killchar != 0) + mode.c_cc[VKILL] = killchar ? killchar : CKILL; +} + +/* + * Set up various conversions in 'mode', including parity, tabs, returns, + * echo, and case, according to the termcap entry. If the program we're + * running was named with a leading upper-case character, map external + * uppercase to internal lowercase. + */ +void +set_conversions(usingupper) + int usingupper; +{ + if (tgetflag("UC") || usingupper) { +#ifdef IUCLC + mode.c_iflag |= IUCLC; + mode.c_oflag |= OLCUC; +#endif + } else if (tgetflag("LC")) { +#ifdef IUCLC + mode.c_iflag &= ~IUCLC; + mode.c_oflag &= ~OLCUC; +#endif + } + mode.c_iflag &= ~(PARMRK | INPCK); + mode.c_lflag |= ICANON; + if (tgetflag("EP")) { + mode.c_cflag |= PARENB; + mode.c_cflag &= ~PARODD; + } + if (tgetflag("OP")) { + mode.c_cflag |= PARENB; + mode.c_cflag |= PARODD; + } + +#ifdef ONLCR + mode.c_oflag |= ONLCR; +#endif + mode.c_iflag |= ICRNL; + mode.c_lflag |= ECHO; + mode.c_oflag |= OXTABS; + if (tgetflag("NL")) { /* Newline, not linefeed. */ +#ifdef ONLCR + mode.c_oflag &= ~ONLCR; +#endif + mode.c_iflag &= ~ICRNL; + } + if (tgetflag("HD")) /* Half duplex. */ + mode.c_lflag &= ~ECHO; + if (tgetflag("pt")) /* Print tabs. */ + mode.c_oflag &= ~OXTABS; + mode.c_lflag |= (ECHOE | ECHOK); +} + +/* Output startup string. */ +void +set_init() +{ + char *bp, buf[1024]; + int settle; + + bp = buf; + if (tgetstr("pc", &bp) != 0) /* Get/set pad character. */ + PC = buf[0]; + +#ifdef TAB3 + if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) { + oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET); + tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode); + } +#endif + settle = set_tabs(); + + if (isreset) { + bp = buf; + if (tgetstr("rs", &bp) != 0 || tgetstr("is", &bp) != 0) { + tputs(buf, 0, outc); + settle = 1; + } + bp = buf; + if (tgetstr("rf", &bp) != 0 || tgetstr("if", &bp) != 0) { + cat(buf); + settle = 1; + } + } + + if (settle) { + (void)putc('\r', stderr); + (void)fflush(stderr); + (void)sleep(1); /* Settle the terminal. */ + } +} + +/* + * Set the hardware tabs on the terminal, using the ct (clear all tabs), + * st (set one tab) and ch (horizontal cursor addressing) capabilities. + * This is done before if and is, so they can patch in case we blow this. + * Return nonzero if we set any tab stops, zero if not. + */ +int +set_tabs() +{ + int c; + char *capsp, *clear_tabs; + char *set_column, *set_pos, *set_tab, *tg_out; + char caps[1024]; + + capsp = caps; + set_tab = tgetstr("st", &capsp); + + if (set_tab && (clear_tabs = tgetstr("ct", &capsp))) { + (void)putc('\r', stderr); /* Force to left margin. */ + tputs(clear_tabs, 0, outc); + } + + set_column = tgetstr("ch", &capsp); + set_pos = set_column ? NULL : tgetstr("cm", &capsp); + + if (set_tab) { + for (c = 8; c < columns; c += 8) { + /* + * Get to the right column. "OOPS" is returned by + * tgoto() if it can't do the job. (*snarl*) + */ + tg_out = "OOPS"; + if (set_column) + tg_out = tgoto(set_column, 0, c); + if (*tg_out == 'O' && set_pos) + tg_out = tgoto(set_pos, c, lines - 1); + if (*tg_out != 'O') + tputs(tg_out, 1, outc); + else + (void)fprintf(stderr, "%s", " "); + /* Set the tab. */ + tputs(set_tab, 0, outc); + } + putc('\r', stderr); + return (1); + } + return (0); +} diff --git a/usr.bin/tset/term.c b/usr.bin/tset/term.c new file mode 100644 index 0000000..dc652e3 --- /dev/null +++ b/usr.bin/tset/term.c @@ -0,0 +1,155 @@ +/*- + * 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[] = "@(#)term.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +char tbuf[1024]; /* Termcap entry. */ + +char *askuser __P((char *)); +char *ttys __P((char *)); + +/* + * Figure out what kind of terminal we're dealing with, and then read in + * its termcap entry. + */ +char * +get_termcap_entry(userarg, tcapbufp) + char *userarg, **tcapbufp; +{ + struct ttyent *t; + int rval; + char *p, *ttype, *ttypath; + + if (userarg) { + ttype = userarg; + goto found; + } + + /* Try the environment. */ + if (ttype = getenv("TERM")) + goto map; + + /* Try ttyname(3); check for dialup or other mapping. */ + if (ttypath = ttyname(STDERR_FILENO)) { + if (p = rindex(ttypath, '/')) + ++p; + else + p = ttypath; + if ((t = getttynam(p))) { + ttype = t->ty_type; + goto map; + } + } + + /* If still undefined, use "unknown". */ + ttype = "unknown"; + +map: ttype = mapped(ttype); + + /* + * If not a path, remove TERMCAP from the environment so we get a + * real entry from /etc/termcap. This prevents us from being fooled + * by out of date stuff in the environment. + */ +found: if ((p = getenv("TERMCAP")) != NULL && *p != '/') + unsetenv("TERMCAP"); + + /* + * ttype now contains a pointer to the type of the terminal. + * If the first character is '?', ask the user. + */ + if (ttype[0] == '?') + if (ttype[1] != '\0') + ttype = askuser(ttype + 1); + else + ttype = askuser(NULL); + + /* Find the termcap entry. If it doesn't exist, ask the user. */ + while ((rval = tgetent(tbuf, ttype)) == 0) { + (void)fprintf(stderr, + "tset: terminal type %s is unknown\n", ttype); + ttype = askuser(NULL); + } + if (rval == -1) + err("termcap: %s", strerror(errno ? errno : ENOENT)); + *tcapbufp = tbuf; + return (ttype); +} + +/* Prompt the user for a terminal type. */ +char * +askuser(dflt) + char *dflt; +{ + static char answer[256]; + char *p; + + /* We can get recalled; if so, don't continue uselessly. */ + if (feof(stdin) || ferror(stdin)) { + (void)fprintf(stderr, "\n"); + exit(1); + } + for (;;) { + if (dflt) + (void)fprintf(stderr, "Terminal type? [%s] ", dflt); + else + (void)fprintf(stderr, "Terminal type? "); + (void)fflush(stderr); + + if (fgets(answer, sizeof(answer), stdin) == NULL) { + if (dflt == NULL) { + (void)fprintf(stderr, "\n"); + exit(1); + } + return (dflt); + } + + if (p = index(answer, '\n')) + *p = '\0'; + if (answer[0]) + return (answer); + if (dflt != NULL) + return (dflt); + } +} diff --git a/usr.bin/tset/tset.1 b/usr.bin/tset/tset.1 new file mode 100644 index 0000000..16b7344 --- /dev/null +++ b/usr.bin/tset/tset.1 @@ -0,0 +1,405 @@ +.\" Copyright (c) 1985, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tset.1 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt TSET 1 +.Os BSD 4 +.Sh NAME +.Nm tset +.Nd terminal initialization +.Sh SYNOPSIS +.Nm tset +.Op Fl IQrSs +.Op Fl +.Op Fl e Ar ch +.Op Fl i Ar ch +.Op Fl k Ar ch +.Op Fl m Ar mapping +.Op Ar terminal +.br +.Nm reset +.Op Fl IQrSs +.Op Fl +.Op Fl e Ar ch +.Op Fl i Ar ch +.Op Fl k Ar ch +.Op Fl m Ar mapping +.Op Ar terminal +.Sh DESCRIPTION +.Nm Tset +initializes terminals. +.Nm Tset +first determines the type of terminal that you are using. +This determination is done as follows, using the first terminal type found. +.sp +.Bl -bullet -compact -offset indent +.It +The +.Ar terminal +argument specified on the command line. +.It +The value of the +.Ev TERM +environmental variable. +.It +The terminal type associated with the standard error output device in the +.Pa /etc/ttys +file. +.It +The default terminal type, ``unknown''. +.El +.Pp +If the terminal type was not specified on the command-line, the +.Fl m +option mappings are then applied (see below for more information). +Then, if the terminal type begins with a question mark (``?''), the user is +prompted for confirmation of the terminal type. +An empty response confirms the type, or, another type can be entered to +specify a new type. +Once the terminal type has been determined, the termcap entry for the terminal +is retrieved. +If no termcap entry is found for the type, the user is prompted for another +terminal type. +.Pp +Once the termcap entry is retrieved, the window size, backspace, interrupt +and line kill characters (among many other things) are set and the terminal +and tab initialization strings are sent to the standard error output. +Finally, if the erase, interrupt and line kill characters have changed, +or are not set to their default values, their values are displayed to the +standard error output. +.Pp +When invoked as +.Nm reset , +.Nm tset +sets cooked and echo modes, turns off cbreak and raw modes, turns on +newline translation and resets any unset special characters to their +default values before doing the terminal initialization described above. +This is useful after a program dies leaving a terminal in a abnormal state. +Note, you may have to type +.Dq Li reset +(the line-feed character is normally control-J) to get the terminal +to work, as carriage-return may no longer work in the abnormal state. +Also, the terminal will often not echo the command. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl +The terminal type is displayed to the standard output, and the terminal is +not initialized in any way. +.It Fl e +Set the erase character to +.Ar ch . +.It Fl I +Do not send the terminal or tab initialization strings to the terminal. +.It Fl i +Set the interrupt character to +.Ar ch . +.It Fl k +Set the line kill character to +.Ar ch . +.It Fl m +Specify a mapping from a port type to a terminal. +See below for more information. +.It Fl Q +Don't display any values for the erase, interrupt and line kill characters. +.It Fl r +Print the terminal type to the standard error output. +.It Fl S +Print the terminal type and the termcap entry to the standard output. +See the section below on setting the environment for details. +.It Fl s +Print the sequence of shell commands to initialize the environment variables +.Ev TERM +and +.Ev TERMCAP +to the standard output. +See the section below on setting the environment for details. +.El +.Pp +The arguments for the +.Fl e , +.Fl i +and +.Fl k +options may either be entered as actual characters or by using the +.Dq hat +notation, i.e. control-h may be specified as +.Dq Li ^H +or +.Dq Li ^h . +.Sh SETTING THE ENVIRONMENT +It is often desirable to enter the terminal type and information about +the terminal's capabilities into the shell's environment. +This is done using the +.Fl S +and +.Fl s +options. +.Pp +When the +.Fl S +option is specified, the terminal type and the termcap entry are written +to the standard output, separated by a space and without a terminating +newline. +This can be assigned to an array by +.Nm csh +and +.Nm ksh +users and then used like any other shell array. +.Pp +When the +.Fl s +option is specified, the commands to enter the information into the +shell's environment are written to the standard output. +If the +.Ev SHELL +environmental variable ends in ``csh'', the commands are for the +.Nm csh , +otherwise, they are for +.Xr sh . +Note, the +.Nm csh +commands set and unset the shell variable +.Dq noglob , +leaving it unset. +The following line in the +.Pa .login +or +.Pa .profile +files will initialize the environment correctly: +.Bd -literal -offset indent +eval \`tset -s options ... \` +.Ed +.Pp +To demonstrate a simple use of the +.Fl S +option, the following lines in the +.Pa .login +file have an equivalent effect: +.Bd -literal -offset indent +set noglob +set term=(`tset -S options ...`) +setenv TERM $term[1] +setenv TERMCAP "$term[2]" +unset term +unset noglob +.Ed +.Sh TERMINAL TYPE MAPPING +When the terminal is not hardwired into the system (or the current system +information is incorrect) the terminal type derived from the +.Pa /etc/ttys +file or the +.Ev TERM +environmental variable is often something generic like +.Dq network , +.Dq dialup , +or +.Dq unknown . +When +.Nm tset +is used in a startup script +.Pf ( Pa .profile +for +.Xr sh 1 +users or +.Pa .login +for +.Xr csh 1 +users) it is often desirable to provide information about the type of +terminal used on such ports. +The purpose of the +.Fl m +option is to +.Dq map +from some set of conditions to a terminal type, that is, to +tell +.Nm tset +``If I'm on this port at a particular speed, guess that I'm on that +kind of terminal''. +.Pp +The argument to the +.Fl m +option consists of an optional port type, an optional operator, an optional +baud rate specification, an optional colon (``:'') character and a terminal +type. +The port type is a string (delimited by either the operator or the colon +character). +The operator may be any combination of: +.Dq Li \&> , +.Dq Li \&< , +.Dq Li \&@ , +and +.Dq Li \&! ; +.Dq Li \&> +means greater than, +.Dq Li \&< +means less than, +.Dq Li \&@ +means equal to +and +.Dq Li \&! +inverts the sense of the test. +The baud rate is specified as a number and is compared with the speed +of the standard error output (which should be the control terminal). +The terminal type is a string. +.Pp +If the terminal type is not specified on the command line, the +.Fl m +mappings are applied to the terminal type. +If the port type and baud rate match the mapping, the terminal type specified +in the mapping replaces the current type. +If more than one mapping is specified, the first applicable mapping is used. +.Pp +For example, consider the following mapping: +.Dq Li dialup>9600:vt100 . +The port type is +.Dq Li dialup , +the operator is +.Dq Li > , +the baud rate specification is +.Dq Li 9600 , +and the terminal type is +.Dq Li vt100 . +The result of this mapping is to specify that if the terminal type is +.Dq Li dialup , +and the baud rate is greater than 9600 baud, a terminal type of +.Dq Li vt100 +will be used. +.Pp +If no port type is specified, the terminal type will match any port type, +for example, +.Dq Li -m dialup:vt100 -m :?xterm +will cause any dialup port, regardless of baud rate, to match the terminal +type +.Dq Li vt100 , +and any non-dialup port type to match the terminal type +.Dq Li ?xterm . +Note, because of the leading question mark, the user will be +queried on a default port as to whether they are actually using an +.Ar xterm +terminal. +.Pp +No whitespace characters are permitted in the +.Fl m +option argument. +Also, to avoid problems with metacharacters, it is suggested that the entire +.Fl m +option argument be placed within single quote characters, and that +.Nm csh +users insert a backslash character (``\e'') before any exclamation +marks (``!''). +.Sh ENVIRONMENT +The +.Nm tset +command utilizes the +.Ev SHELL +and +.Ev TERM +environment variables. +.Sh FILES +.Bl -tag -width /usr/share/misc/termcap -compact +.It Pa /etc/ttys +system port name to terminal type mapping database +.It Pa /usr/share/misc/termcap +terminal capability database +.El +.Sh SEE ALSO +.Xr csh 1 , +.Xr sh 1 , +.Xr stty 1 , +.Xr tty 4 , +.Xr termcap 5 , +.Xr ttys 5 , +.Xr environ 7 +.Sh HISTORY +The +.Nm tset +command appeared in +.Bx 3.0 . +.Sh COMPATIBILITY +The +.Fl A , +.Fl E , +.Fl h , +.Fl u +and +.Fl v +options have been deleted from the +.Nm tset +utility. +None of them were documented in 4.3BSD and all are of limited utility at +best. +The +.Fl a , +.Fl d +and +.Fl p +options are similarly not documented or useful, but were retained as they +appear to be in widespread use. +It is strongly recommended that any usage of these three options be +changed to use the +.Fl m +option instead. +The +.Fl n +option remains, but has no effect. +It is still permissible to specify the +.Fl e , +.Fl i +and +.Fl k +options without arguments, although it is strongly recommended that such +usage be fixed to explicitly specify the character. +.Pp +Executing +.Nm tset +as +.Nm reset +no longer implies the +.Fl Q +option. +Also, the interaction between the +.Fl +option and the +.Ar terminal +argument in some historic implementations of +.Nm tset +has been removed. +.Pp +Finally, the +.Nm tset +implementation has been completely redone (as part of the addition to the +system of a +.St -p1003.1-88 +compliant terminal interface) and will no longer compile on systems with +older terminal interfaces. diff --git a/usr.bin/tset/tset.c b/usr.bin/tset/tset.c new file mode 100644 index 0000000..7198e96 --- /dev/null +++ b/usr.bin/tset/tset.c @@ -0,0 +1,303 @@ +/*- + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tset.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "extern.h" + +void obsolete __P((char *[])); +void report __P((char *, int, u_int)); +void usage __P((void)); + +struct termios mode, oldmode; + +int erasechar; /* new erase character */ +int intrchar; /* new interrupt character */ +int isreset; /* invoked as reset */ +int killchar; /* new kill character */ +int lines, columns; /* window size */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef TIOCGWINSZ + struct winsize win; +#endif + int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper; + char savech, *p, *t, *tcapbuf, *ttype; + + if (tcgetattr(STDERR_FILENO, &mode) < 0) + err("standard error: %s", strerror(errno)); + + oldmode = mode; + ospeed = cfgetospeed(&mode); + + if (p = strrchr(*argv, '/')) + ++p; + else + p = *argv; + usingupper = isupper(*p); + if (!strcasecmp(p, "reset")) { + isreset = 1; + reset_mode(); + } + + obsolete(argv); + noinit = noset = quiet = Sflag = sflag = showterm = 0; + while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != EOF) { + switch (ch) { + case '-': /* display term only */ + noset = 1; + break; + case 'a': /* OBSOLETE: map identifier to type */ + add_mapping("arpanet", optarg); + break; + case 'd': /* OBSOLETE: map identifier to type */ + add_mapping("dialup", optarg); + break; + case 'e': /* erase character */ + erasechar = optarg[0] == '^' && optarg[1] != '\0' ? + optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : + optarg[0]; + break; + case 'I': /* no initialization strings */ + noinit = 1; + break; + case 'i': /* interrupt character */ + intrchar = optarg[0] == '^' && optarg[1] != '\0' ? + optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : + optarg[0]; + break; + case 'k': /* kill character */ + killchar = optarg[0] == '^' && optarg[1] != '\0' ? + optarg[1] == '?' ? '\177' : CTRL(optarg[1]) : + optarg[0]; + break; + case 'm': /* map identifier to type */ + add_mapping(NULL, optarg); + break; + case 'n': /* OBSOLETE: set new tty driver */ + break; + case 'p': /* OBSOLETE: map identifier to type */ + add_mapping("plugboard", optarg); + break; + case 'Q': /* don't output control key settings */ + quiet = 1; + break; + case 'S': /* output TERM/TERMCAP strings */ + Sflag = 1; + break; + case 'r': /* display term on stderr */ + showterm = 1; + break; + case 's': /* output TERM/TERMCAP strings */ + sflag = 1; + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + usage(); + + ttype = get_termcap_entry(*argv, &tcapbuf); + + if (!noset) { + columns = tgetnum("co"); + lines = tgetnum("li"); + +#ifdef TIOCGWINSZ + /* Set window size */ + (void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win); + if (win.ws_row == 0 && win.ws_col == 0 && + lines > 0 && columns > 0) { + win.ws_row = lines; + win.ws_col = columns; + (void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win); + } +#endif + set_control_chars(); + set_conversions(usingupper); + + if (!noinit) + set_init(); + + /* Set the modes if they've changed. */ + if (memcmp(&mode, &oldmode, sizeof(mode))) + tcsetattr(STDERR_FILENO, TCSADRAIN, &mode); + } + + /* Get the terminal name from the entry. */ + p = tcapbuf; + if (p != NULL && *p != ':') { + t = p; + if (p = strpbrk(p, "|:")) { + savech = *p; + *p = '\0'; + if ((ttype = strdup(t)) == NULL) + err("%s", strerror(errno)); + *p = savech; + } + } + + if (noset) + (void)printf("%s\n", ttype); + else { + if (showterm) + (void)fprintf(stderr, "Terminal type is %s.\n", ttype); + /* + * If erase, kill and interrupt characters could have been + * modified and not -Q, display the changes. + */ + if (!quiet) { + report("Erase", VERASE, CERASE); + report("Kill", VKILL, CKILL); + report("Interrupt", VINTR, CINTR); + } + } + + if (Sflag) { + (void)printf("%s ", ttype); + wrtermcap(tcapbuf); + } + + if (sflag) { + /* + * Figure out what shell we're using. A hack, we look for an + * environmental variable SHELL ending in "csh". + */ + if ((p = getenv("SHELL")) && + !strcmp(p + strlen(p) - 3, "csh")) { + p = "set noglob;\nsetenv TERM %s;\nsetenv TERMCAP '"; + t = "';\nunset noglob;\n"; + } else { + p = "TERM=%s;\nTERMCAP='"; + t = "';\nexport TERMCAP TERM;\n"; + } + (void)printf(p, ttype); + wrtermcap(tcapbuf); + (void)printf(t); + } + + exit(0); +} + +/* + * Tell the user if a control key has been changed from the default value. + */ +void +report(name, which, def) + char *name; + int which; + u_int def; +{ + u_int old, new; + char *bp, buf[1024]; + + new = mode.c_cc[which]; + old = oldmode.c_cc[which]; + + if (old == new && old == def) + return; + + (void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to"); + + bp = buf; + if (tgetstr("kb", &bp) && new == buf[0] && buf[1] == '\0') + (void)fprintf(stderr, "backspace.\n"); + else if (new == 0177) + (void)fprintf(stderr, "delete.\n"); + else if (new < 040) { + new ^= 0100; + (void)fprintf(stderr, "control-%c (^%c).\n", new, new); + } else + (void)fprintf(stderr, "%c.\n", new); +} + +/* + * Convert the obsolete argument form into something that getopt can handle. + * This means that -e, -i and -k get default arguments supplied for them. + */ +void +obsolete(argv) + char *argv[]; +{ + for (; *argv; ++argv) { + if (argv[0][0] != '-' || argv[1] && argv[1][0] != '-' || + argv[0][1] != 'e' && argv[0][1] != 'i' && + argv[0][1] != 'k' || argv[0][2] != '\0') + continue; + switch(argv[0][1]) { + case 'e': + argv[0] = "-e^H"; + break; + case 'i': + argv[0] = "-i^C"; + break; + case 'k': + argv[0] = "-k^U"; + break; + } + } +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: tset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n"); + exit(1); +} diff --git a/usr.bin/tset/wrterm.c b/usr.bin/tset/wrterm.c new file mode 100644 index 0000000..5c33b49 --- /dev/null +++ b/usr.bin/tset/wrterm.c @@ -0,0 +1,112 @@ +/*- + * 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[] = "@(#)wrterm.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include "extern.h" + +/* + * Output termcap entry to stdout, quoting characters that would give the + * shell problems and omitting empty fields. + */ +void +wrtermcap(bp) + char *bp; +{ + register int ch; + register char *p; + char *t, *sep; + + /* Find the end of the terminal names. */ + if ((t = index(bp, ':')) == NULL) + err("termcap names not colon terminated"); + *t++ = '\0'; + + /* Output terminal names that don't have whitespace. */ + sep = ""; + while ((p = strsep(&bp, "|")) != NULL) + if (*p != '\0' && strpbrk(p, " \t") == NULL) { + (void)printf("%s%s", sep, p); + sep = "|"; + } + (void)putchar(':'); + + /* + * Output fields, transforming any dangerous characters. Skip + * empty fields or fields containing only whitespace. + */ + while ((p = strsep(&t, ":")) != NULL) { + while ((ch = *p) != '\0' && isspace(ch)) + ++p; + if (ch == '\0') + continue; + while ((ch = *p++) != '\0') + switch(ch) { + case '\033': + (void)printf("\\E"); + case ' ': /* No spaces. */ + (void)printf("\\040"); + break; + case '!': /* No csh history chars. */ + (void)printf("\\041"); + break; + case ',': /* No csh history chars. */ + (void)printf("\\054"); + break; + case '"': /* No quotes. */ + (void)printf("\\042"); + break; + case '\'': /* No quotes. */ + (void)printf("\\047"); + break; + case '`': /* No quotes. */ + (void)printf("\\140"); + break; + case '\\': /* Anything following is OK. */ + case '^': + (void)putchar(ch); + if ((ch = *p++) == '\0') + break; + /* FALLTHROUGH */ + default: + (void)putchar(ch); + } + (void)putchar(':'); + } +} diff --git a/usr.bin/tsort/Makefile b/usr.bin/tsort/Makefile new file mode 100644 index 0000000..e00f9ac --- /dev/null +++ b/usr.bin/tsort/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= tsort + +.include diff --git a/usr.bin/tsort/tsort.1 b/usr.bin/tsort/tsort.1 new file mode 100644 index 0000000..f3eb74b --- /dev/null +++ b/usr.bin/tsort/tsort.1 @@ -0,0 +1,83 @@ +.\" Copyright (c) 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This manual is derived from one contributed to Berkeley by +.\" Michael Rendell of Memorial University of Newfoundland. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tsort.1 8.3 (Berkeley) 4/1/94 +.\" +.Dd April 1, 1994 +.Dt TSORT 1 +.Os +.Sh NAME +.Nm tsort +.Nd topological sort of a directed graph +.Sh SYNOPSIS +.Nm tsort +.Op Fl l +.Op Ar file +.Sh DESCRIPTION +.Nm Tsort +takes a list of pairs of node names representing directed arcs in +a graph and prints the nodes in topological order on standard output. +Input is taken from the named +.Ar file , +or from standard input if no file +is given. +.Pp +Node names in the input are separated by white space and there must +be an even number of node pairs. +.Pp +Presence of a node in a graph can be represented by an arc from the node +to itself. +This is useful when a node is not connected to any other nodes. +.Pp +If the graph contains a cycle (and therefore cannot be properly sorted), +one of the arcs in the cycle is ignored and the sort continues. +Cycles are reported on standard error. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl l +Search for and display the longest cycle. +Can take a very long time. +.El +.Sh SEE ALSO +.Xr ar 1 +.Sh HISTORY +A +.Nm +command appeared in +.At v7 . +This +.Nm tsort +command and manual page are derived from sources contributed to Berkeley by +Michael Rendell of Memorial University of Newfoundland. diff --git a/usr.bin/tsort/tsort.c b/usr.bin/tsort/tsort.c new file mode 100644 index 0000000..133614c --- /dev/null +++ b/usr.bin/tsort/tsort.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Rendell of Memorial University of Newfoundland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tsort.c 8.2 (Berkeley) 3/30/94"; +#endif /* not lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Topological sort. Input is a list of pairs of strings separated by + * white space (spaces, tabs, and/or newlines); strings are written to + * standard output in sorted order, one per line. + * + * usage: + * tsort [-l] [inputfile] + * If no input file is specified, standard input is read. + * + * Should be compatable with AT&T tsort HOWEVER the output is not identical + * (i.e. for most graphs there is more than one sorted order, and this tsort + * usually generates a different one then the AT&T tsort). Also, cycle + * reporting seems to be more accurate in this version (the AT&T tsort + * sometimes says a node is in a cycle when it isn't). + * + * Michael Rendell, michael@stretch.cs.mun.ca - Feb 26, '90 + */ +#define HASHSIZE 53 /* doesn't need to be big */ +#define NF_MARK 0x1 /* marker for cycle detection */ +#define NF_ACYCLIC 0x2 /* this node is cycle free */ +#define NF_NODEST 0x4 /* Unreachable */ + + +typedef struct node_str NODE; + +struct node_str { + NODE **n_prevp; /* pointer to previous node's n_next */ + NODE *n_next; /* next node in graph */ + NODE **n_arcs; /* array of arcs to other nodes */ + int n_narcs; /* number of arcs in n_arcs[] */ + int n_arcsize; /* size of n_arcs[] array */ + int n_refcnt; /* # of arcs pointing to this node */ + int n_flags; /* NF_* */ + char n_name[1]; /* name of this node */ +}; + +typedef struct _buf { + char *b_buf; + int b_bsize; +} BUF; + +DB *db; +NODE *graph, **cycle_buf, **longest_cycle; +int debug, longest; + +void add_arc __P((char *, char *)); +int find_cycle __P((NODE *, NODE *, int, int)); +NODE *get_node __P((char *)); +void *grow_buf __P((void *, int)); +void remove_node __P((NODE *)); +void tsort __P((void)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register BUF *b; + register int c, n; + FILE *fp; + int bsize, ch, nused; + BUF bufs[2]; + + while ((ch = getopt(argc, argv, "dl")) != EOF) + switch (ch) { + case 'd': + debug = 1; + break; + case 'l': + longest = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + switch (argc) { + case 0: + fp = stdin; + break; + case 1: + if ((fp = fopen(*argv, "r")) == NULL) + err(1, "%s", *argv); + break; + default: + usage(); + } + + for (b = bufs, n = 2; --n >= 0; b++) + b->b_buf = grow_buf(NULL, b->b_bsize = 1024); + + /* parse input and build the graph */ + for (n = 0, c = getc(fp);;) { + while (c != EOF && isspace(c)) + c = getc(fp); + if (c == EOF) + break; + + nused = 0; + b = &bufs[n]; + bsize = b->b_bsize; + do { + b->b_buf[nused++] = c; + if (nused == bsize) + b->b_buf = grow_buf(b->b_buf, bsize *= 2); + c = getc(fp); + } while (c != EOF && !isspace(c)); + + b->b_buf[nused] = '\0'; + b->b_bsize = bsize; + if (n) + add_arc(bufs[0].b_buf, bufs[1].b_buf); + n = !n; + } + (void)fclose(fp); + if (n) + errx(1, "odd data count"); + + /* do the sort */ + tsort(); + exit(0); +} + +/* double the size of oldbuf and return a pointer to the new buffer. */ +void * +grow_buf(bp, size) + void *bp; + int size; +{ + if ((bp = realloc(bp, (u_int)size)) == NULL) + err(1, NULL); + return (bp); +} + +/* + * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in + * the graph, then add them. + */ +void +add_arc(s1, s2) + char *s1, *s2; +{ + register NODE *n1; + NODE *n2; + int bsize, i; + + n1 = get_node(s1); + + if (!strcmp(s1, s2)) + return; + + n2 = get_node(s2); + + /* + * Check if this arc is already here. + */ + for (i = 0; i < n1->n_narcs; i++) + if (n1->n_arcs[i] == n2) + return; + /* + * Add it. + */ + if (n1->n_narcs == n1->n_arcsize) { + if (!n1->n_arcsize) + n1->n_arcsize = 10; + bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2; + n1->n_arcs = grow_buf(n1->n_arcs, bsize); + n1->n_arcsize = bsize / sizeof(*n1->n_arcs); + } + n1->n_arcs[n1->n_narcs++] = n2; + ++n2->n_refcnt; +} + +/* Find a node in the graph (insert if not found) and return a pointer to it. */ +NODE * +get_node(name) + char *name; +{ + DBT data, key; + NODE *n; + + if (db == NULL && + (db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL) + err(1, "db: %s", name); + + key.data = name; + key.size = strlen(name) + 1; + + switch ((*db->get)(db, &key, &data, 0)) { + case 0: + bcopy(data.data, &n, sizeof(n)); + return (n); + case 1: + break; + default: + case -1: + err(1, "db: %s", name); + } + + if ((n = malloc(sizeof(NODE) + key.size)) == NULL) + err(1, NULL); + + n->n_narcs = 0; + n->n_arcsize = 0; + n->n_arcs = NULL; + n->n_refcnt = 0; + n->n_flags = 0; + bcopy(name, n->n_name, key.size); + + /* Add to linked list. */ + if ((n->n_next = graph) != NULL) + graph->n_prevp = &n->n_next; + n->n_prevp = &graph; + graph = n; + + /* Add to hash table. */ + data.data = &n; + data.size = sizeof(n); + if ((*db->put)(db, &key, &data, 0)) + err(1, "db: %s", name); + return (n); +} + + +/* + * Clear the NODEST flag from all nodes. + */ +void +clear_cycle() +{ + NODE *n; + + for (n = graph; n != NULL; n = n->n_next) + n->n_flags &= ~NF_NODEST; +} + +/* do topological sort on graph */ +void +tsort() +{ + register NODE *n, *next; + register int cnt, i; + + while (graph != NULL) { + /* + * Keep getting rid of simple cases until there are none left, + * if there are any nodes still in the graph, then there is + * a cycle in it. + */ + do { + for (cnt = 0, n = graph; n != NULL; n = next) { + next = n->n_next; + if (n->n_refcnt == 0) { + remove_node(n); + ++cnt; + } + } + } while (graph != NULL && cnt); + + if (graph == NULL) + break; + + if (!cycle_buf) { + /* + * Allocate space for two cycle logs - one to be used + * as scratch space, the other to save the longest + * cycle. + */ + for (cnt = 0, n = graph; n != NULL; n = n->n_next) + ++cnt; + cycle_buf = malloc((u_int)sizeof(NODE *) * cnt); + longest_cycle = malloc((u_int)sizeof(NODE *) * cnt); + if (cycle_buf == NULL || longest_cycle == NULL) + err(1, NULL); + } + for (n = graph; n != NULL; n = n->n_next) + if (!(n->n_flags & NF_ACYCLIC)) + if (cnt = find_cycle(n, n, 0, 0)) { + warnx("cycle in data"); + for (i = 0; i < cnt; i++) + warnx("%s", + longest_cycle[i]->n_name); + remove_node(n); + clear_cycle(); + break; + } else { + /* to avoid further checks */ + n->n_flags |= NF_ACYCLIC; + clear_cycle(); + } + + if (n == NULL) + errx(1, "internal error -- could not find cycle"); + } +} + +/* print node and remove from graph (does not actually free node) */ +void +remove_node(n) + register NODE *n; +{ + register NODE **np; + register int i; + + (void)printf("%s\n", n->n_name); + for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++) + --(*np)->n_refcnt; + n->n_narcs = 0; + *n->n_prevp = n->n_next; + if (n->n_next) + n->n_next->n_prevp = n->n_prevp; +} + + +/* look for the longest? cycle from node from to node to. */ +int +find_cycle(from, to, longest_len, depth) + NODE *from, *to; + int depth, longest_len; +{ + register NODE **np; + register int i, len; + + /* + * avoid infinite loops and ignore portions of the graph known + * to be acyclic + */ + if (from->n_flags & (NF_NODEST|NF_MARK|NF_ACYCLIC)) + return (0); + from->n_flags |= NF_MARK; + + for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) { + cycle_buf[depth] = *np; + if (*np == to) { + if (depth + 1 > longest_len) { + longest_len = depth + 1; + (void)memcpy((char *)longest_cycle, + (char *)cycle_buf, + longest_len * sizeof(NODE *)); + } + } else { + if ((*np)->n_flags & (NF_MARK|NF_ACYCLIC|NF_NODEST)) + continue; + len = find_cycle(*np, to, longest_len, depth + 1); + + if (debug) + (void)printf("%*s %s->%s %d\n", depth, "", + from->n_name, to->n_name, len); + + if (len == 0) + (*np)->n_flags |= NF_NODEST; + + if (len > longest_len) + longest_len = len; + + if (len > 0 && !longest) + break; + } + } + from->n_flags &= ~NF_MARK; + return (longest_len); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: tsort [-l] [file]\n"); + exit(1); +} diff --git a/usr.bin/tty/Makefile b/usr.bin/tty/Makefile new file mode 100644 index 0000000..5b914b2 --- /dev/null +++ b/usr.bin/tty/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= tty + +.include diff --git a/usr.bin/tty/tty.1 b/usr.bin/tty/tty.1 new file mode 100644 index 0000000..9607c11 --- /dev/null +++ b/usr.bin/tty/tty.1 @@ -0,0 +1,78 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)tty.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt TTY 1 +.Os +.Sh NAME +.Nm tty +.Nd return user's terminal name +.Sh SYNOPSIS +.Nm tty +.Op Fl s +.Sh DESCRIPTION +The +.Nm tty +utility writes the name of the terminal attached to standard input +to standard output. +The name that is written is the string returned by +.Xr ttyname 3 . +If the standard input is not a terminal, the message ``not a tty'' +is written. +The options are as follows: +.Bl -tag -width Ds +.It Fl s +Don't write the terminal name; only the exit status is affected +when this option is specified. +The +.Fl s +option is deprecated in favor of the +.Dq Li "test -t 0" +command. +.El +.Pp +.Nm Tty +exits 0 if the standard input is a terminal, 1 if the standard input is +not a terminal, and >1 if an error occurs. +.Sh SEE ALSO +.Xr test 1 , +.Xr ttyname 3 +.Sh STANDARDS +The +.Nm tty +function is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/tty/tty.c b/usr.bin/tty/tty.c new file mode 100644 index 0000000..d07cab7 --- /dev/null +++ b/usr.bin/tty/tty.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +main(argc, argv) + int argc; + char **argv; +{ + int ch, sflag; + char *t, *ttyname(); + + sflag = 0; + while ((ch = getopt(argc, argv, "s")) != EOF) + switch((char)ch) { + case 's': + sflag = 1; + break; + case '?': + default: + fputs("usage: tty [-s]\n", stderr); + exit(2); + } + + t = ttyname(0); + if (!sflag) + puts(t ? t : "not a tty"); + exit(t ? 0 : 1); +} diff --git a/usr.bin/ul/Makefile b/usr.bin/ul/Makefile new file mode 100644 index 0000000..645c291 --- /dev/null +++ b/usr.bin/ul/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= ul +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap + +.include diff --git a/usr.bin/ul/ul.1 b/usr.bin/ul/ul.1 new file mode 100644 index 0000000..701797a --- /dev/null +++ b/usr.bin/ul/ul.1 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)ul.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UL 1 +.Os BSD 4 +.Sh NAME +.Nm ul +.Nd do underlining +.Sh SYNOPSIS +.Nm ul +.Op Fl i +.Op Fl t Ar terminal +.Op Ar name Ar ... +.Sh DESCRIPTION +.Nm Ul +reads the named files (or standard input if none are given) +and translates occurrences of underscores to the sequence +which indicates underlining for the terminal in use, as specified +by the environment variable +.Ev TERM . +The file +.Pa /etc/termcap +is read to determine the appropriate sequences for underlining. +If the terminal is incapable of underlining, but is capable of +a standout mode then that is used instead. +If the terminal can overstrike, +or handles underlining automatically, +.Nm ul +degenerates to +.Xr cat 1 . +If the terminal cannot underline, underlining is ignored. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl i +Underlining is indicated by a separate line containing appropriate +dashes `\-'; this is useful when you want to look at the underlining +which is present in an +.Xr nroff +output stream on a crt-terminal. +.It Fl t Ar terminal +Overrides the terminal type specified in the environment with +.Ar terminal . +.El +.Sh ENVIRONMENT +The following environment variable is used: +.Bl -tag -width TERM +.It Ev TERM +The +.Ev TERM +variable is used to relate a tty device +with its device capability description (see +.Xr termcap 5 ) . +.Ev TERM +is set at login time, either by the default terminal type +specified in +.Pa /etc/ttys +or as set during the login process by the user in their +.Pa login +file (see +.Xr setenv 1 ) . +.El +.Sh SEE ALSO +.Xr man 1 , +.Xr nroff 1 , +.Xr colcrt 1 +.Sh BUGS +.Xr Nroff +usually outputs a series of backspaces and underlines intermixed +with the text to indicate underlining. No attempt is made to optimize +the backward motion. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/ul/ul.c b/usr.bin/ul/ul.c new file mode 100644 index 0000000..75e6f95 --- /dev/null +++ b/usr.bin/ul/ul.c @@ -0,0 +1,508 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +#define IESC '\033' +#define SO '\016' +#define SI '\017' +#define HFWD '9' +#define HREV '8' +#define FREV '7' +#define MAXBUF 512 + +#define NORMAL 000 +#define ALTSET 001 /* Reverse */ +#define SUPERSC 002 /* Dim */ +#define SUBSC 004 /* Dim | Ul */ +#define UNDERL 010 /* Ul */ +#define BOLD 020 /* Bold */ + +int must_use_uc, must_overstrike; +char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, + *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, + *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; + +struct CHAR { + char c_mode; + char c_char; +} ; + +struct CHAR obuf[MAXBUF]; +int col, maxcol; +int mode; +int halfpos; +int upln; +int iflag; + +int outchar(); +#define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar) + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + extern char *optarg; + int c; + char *termtype; + FILE *f; + char termcap[1024]; + char *getenv(), *strcpy(); + + termtype = getenv("TERM"); + if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) + termtype = "lpr"; + while ((c=getopt(argc, argv, "it:T:")) != EOF) + switch(c) { + + case 't': + case 'T': /* for nroff compatibility */ + termtype = optarg; + break; + case 'i': + iflag = 1; + break; + + default: + fprintf(stderr, + "usage: %s [ -i ] [ -tTerm ] file...\n", + argv[0]); + exit(1); + } + + switch(tgetent(termcap, termtype)) { + + case 1: + break; + + default: + fprintf(stderr,"trouble reading termcap"); + /* fall through to ... */ + + case 0: + /* No such terminal type - assume dumb */ + (void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:"); + break; + } + initcap(); + if ( (tgetflag("os") && ENTER_BOLD==NULL ) || + (tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) + must_overstrike = 1; + initbuf(); + if (optind == argc) + filter(stdin); + else for (; optind 0) + col--; + continue; + + case '\t': + col = (col+8) & ~07; + if (col > maxcol) + maxcol = col; + continue; + + case '\r': + col = 0; + continue; + + case SO: + mode |= ALTSET; + continue; + + case SI: + mode &= ~ALTSET; + continue; + + case IESC: + switch (c = getc(f)) { + + case HREV: + if (halfpos == 0) { + mode |= SUPERSC; + halfpos--; + } else if (halfpos > 0) { + mode &= ~SUBSC; + halfpos--; + } else { + halfpos = 0; + reverse(); + } + continue; + + case HFWD: + if (halfpos == 0) { + mode |= SUBSC; + halfpos++; + } else if (halfpos < 0) { + mode &= ~SUPERSC; + halfpos++; + } else { + halfpos = 0; + fwd(); + } + continue; + + case FREV: + reverse(); + continue; + + default: + fprintf(stderr, + "Unknown escape sequence in input: %o, %o\n", + IESC, c); + exit(1); + } + continue; + + case '_': + if (obuf[col].c_char) + obuf[col].c_mode |= UNDERL | mode; + else + obuf[col].c_char = '_'; + case ' ': + col++; + if (col > maxcol) + maxcol = col; + continue; + + case '\n': + flushln(); + continue; + + case '\f': + flushln(); + putchar('\f'); + continue; + + default: + if (c < ' ') /* non printing */ + continue; + if (obuf[col].c_char == '\0') { + obuf[col].c_char = c; + obuf[col].c_mode = mode; + } else if (obuf[col].c_char == '_') { + obuf[col].c_char = c; + obuf[col].c_mode |= UNDERL|mode; + } else if (obuf[col].c_char == c) + obuf[col].c_mode |= BOLD|mode; + else + obuf[col].c_mode = mode; + col++; + if (col > maxcol) + maxcol = col; + continue; + } + if (maxcol) + flushln(); +} + +flushln() +{ + register lastmode; + register i; + int hadmodes = 0; + + lastmode = NORMAL; + for (i=0; i diff --git a/usr.bin/uname/uname.1 b/usr.bin/uname/uname.1 new file mode 100644 index 0000000..50e0c52 --- /dev/null +++ b/usr.bin/uname/uname.1 @@ -0,0 +1,97 @@ +.\" 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. +.\" +.\" @(#)uname.1 8.3 (Berkeley) 4/8/94 +.\" +.Dd "April 8, 1994" +.Dt UNAME 1 +.Os +.Sh NAME +.Nm uname +.Nd display information about the system +.Sh SYNOPSIS +.Nm uname +.Op Fl amnrsv +.Sh DESCRIPTION +The +.Nm uname +command writes the name of the operating system implementation to +standard output. +When options are specified, strings representing one or more system +characteristics are written to standard output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Behave as though the options +.Fl m , +.Fl n , +.Fl r , +.Fl s , +and +.Fl v +were specified. +.It Fl m +Write the type of the current hardware platform to standard output. +.It Fl n +Write the name of the system to standard output. +.It Fl r +Write the current release level of the operating system +to standard output. +.It Fl s +Write the name of the operating system implementation to standard output. +.It Fl v +Write the version level of this release of the operating system +to standard output. +.El +.Pp +If the +.Fl a +flag is specified, or multiple flags are specified, all +output is written on a single line, separated by spaces. +.Pp +The +.Nm uname +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr sysctl 8 , +.Xr sysctl 3 , +.Xr uname 3 +.Sh HISTORY +The +.Nm uname +command appeared in 4.4BSD. +.Sh STANDARDS +The +.Nm uname +command is expected to conform to the +.St -p1003.2 +specification. diff --git a/usr.bin/uname/uname.c b/usr.bin/uname/uname.c new file mode 100644 index 0000000..2ee1547 --- /dev/null +++ b/usr.bin/uname/uname.c @@ -0,0 +1,162 @@ +/*- + * 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 copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uname.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include + +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ +#define MFLAG 0x01 +#define NFLAG 0x02 +#define RFLAG 0x04 +#define SFLAG 0x08 +#define VFLAG 0x10 + u_int flags; + int ch, mib[2]; + size_t len, tlen; + char *p, *prefix, buf[1024]; + + flags = 0; + while ((ch = getopt(argc, argv, "amnrsv")) != EOF) + switch(ch) { + case 'a': + flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG); + break; + case 'm': + flags |= MFLAG; + break; + case 'n': + flags |= NFLAG; + break; + case 'r': + flags |= RFLAG; + break; + case 's': + flags |= SFLAG; + break; + case 'v': + flags |= VFLAG; + break; + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc) + usage(); + + if (!flags) + flags |= SFLAG; + + prefix = ""; + + if (flags & SFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_OSTYPE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) + err(1, "sysctl"); + (void)printf("%s%.*s", prefix, len, buf); + prefix = " "; + } + if (flags & NFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) + err(1, "sysctl"); + (void)printf("%s%.*s", prefix, len, buf); + prefix = " "; + } + if (flags & RFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) + err(1, "sysctl"); + (void)printf("%s%.*s", prefix, len, buf); + prefix = " "; + } + if (flags & VFLAG) { + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) + err(1, "sysctl"); + for (p = buf, tlen = len; tlen--; ++p) + if (*p == '\n' || *p == '\t') + *p = ' '; + (void)printf("%s%.*s", prefix, len, buf); + prefix = " "; + } + if (flags & MFLAG) { + mib[0] = CTL_HW; + mib[1] = HW_MACHINE; + len = sizeof(buf); + if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1) + err(1, "sysctl"); + (void)printf("%s%.*s", prefix, len, buf); + prefix = " "; + } + (void)printf("\n"); + exit (0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: uname [-amnrsv]\n"); + exit(1); +} diff --git a/usr.bin/unexpand/Makefile b/usr.bin/unexpand/Makefile new file mode 100644 index 0000000..d634f96 --- /dev/null +++ b/usr.bin/unexpand/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= unexpand +NOMAN= noman + +.include diff --git a/usr.bin/unexpand/unexpand.c b/usr.bin/unexpand/unexpand.c new file mode 100644 index 0000000..1078dc2 --- /dev/null +++ b/usr.bin/unexpand/unexpand.c @@ -0,0 +1,131 @@ +/*- + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)unexpand.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * unexpand - put tabs into a file replacing blanks + */ +#include + +char genbuf[BUFSIZ]; +char linebuf[BUFSIZ]; +int all; + +main(argc, argv) + int argc; + char *argv[]; +{ + register char *cp; + + argc--, argv++; + if (argc > 0 && argv[0][0] == '-') { + if (strcmp(argv[0], "-a") != 0) { + fprintf(stderr, "usage: unexpand [ -a ] file ...\n"); + exit(1); + } + all++; + argc--, argv++; + } + do { + if (argc > 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + perror(argv[0]); + exit(1); + } + argc--, argv++; + } + while (fgets(genbuf, BUFSIZ, stdin) != NULL) { + for (cp = linebuf; *cp; cp++) + continue; + if (cp > linebuf) + cp[-1] = 0; + tabify(all); + printf("%s", linebuf); + } + } while (argc > 0); + exit(0); +} + +tabify(c) + char c; +{ + register char *cp, *dp; + register int dcol; + int ocol; + + ocol = 0; + dcol = 0; + cp = genbuf, dp = linebuf; + for (;;) { + switch (*cp) { + + case ' ': + dcol++; + break; + + case '\t': + dcol += 8; + dcol &= ~07; + break; + + default: + while (((ocol + 8) &~ 07) <= dcol) { + if (ocol + 1 == dcol) + break; + *dp++ = '\t'; + ocol += 8; + ocol &= ~07; + } + while (ocol < dcol) { + *dp++ = ' '; + ocol++; + } + if (*cp == 0 || c == 0) { + strcpy(dp, cp); + return; + } + *dp++ = *cp; + ocol++, dcol++; + } + cp++; + } +} diff --git a/usr.bin/unifdef/Makefile b/usr.bin/unifdef/Makefile new file mode 100644 index 0000000..88c14fc --- /dev/null +++ b/usr.bin/unifdef/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= unifdef + +.include diff --git a/usr.bin/unifdef/unifdef.1 b/usr.bin/unifdef/unifdef.1 new file mode 100644 index 0000000..c27a9fd --- /dev/null +++ b/usr.bin/unifdef/unifdef.1 @@ -0,0 +1,165 @@ +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Dave Yost. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)unifdef.1 8.2 (Berkeley) 4/1/94 +.\" +.Dd April 1, 1994 +.Dt UNIFDEF 1 +.Os BSD 4.3 +.Sh NAME +.Nm unifdef +.Nd remove ifdef'ed lines +.Sh SYNOPSIS +.Nm unifdef +.Op Fl clt +.Oo +.Fl D Ns Ar sym +.Fl U Ns Ar sym +.Fl iD Ns Ar sym +.Fl iD Ns Ar sym +.Oc +.Ar ... +.Op Ar file +.Sh DESCRIPTION +.Nm Unifdef +is useful for removing ifdef'ed lines +from a file while otherwise leaving the file alone. +.Nm Unifdef +acts on +#ifdef, #ifndef, #else, and #endif lines, +and it knows only enough about C +to know when one of these is inactive +because it is inside +a comment, +or a single or double quote. +Parsing for quotes is very simplistic: +when it finds an open quote, +it ignores everything (except escaped quotes) +until it finds a close quote, and +it will not complain if it gets +to the end of a line and finds no backslash for continuation. +.Pp +Available options: +.Bl -tag -width Ds -compact +.It Fl D Ns Ar sym +.It Fl U Ns Ar sym +Specify which symbols to define or undefine. +and the lines inside those ifdefs will be copied to the output or removed as +appropriate. +The ifdef, ifndef, else, and endif lines associated with +.Ar sym +will also be removed. +Ifdefs involving symbols you don't specify +and ``#if'' control lines +are untouched and copied out +along with their associated +ifdef, else, and endif lines. +If an ifdef X occurs nested inside another ifdef X, then the +inside ifdef is treated as if it were an unrecognized symbol. +If the same symbol appears in more than one argument, +the last occurrence dominates. +.Pp +.It Fl c +If the +.Fl c +flag is specified, +then the operation of +.Nm unifdef +is complemented, +i.e. the lines that would have been removed or blanked +are retained and vice versa. +.Pp +.It Fl l +Replace removed lines with blank lines +instead of deleting them. +.It Fl t +Disables parsing for C comments and quotes, which is useful +for plain text. +.Pp +.It Fl iD Ns Ar sym +.It Fl iU Ns Ar sym +Ignore ifdefs. +If your C code uses ifdefs to delimit non-C lines, +such as comments +or code which is under construction, +then you must tell +.Nm unifdef +which symbols are used for that purpose so that it won't try to parse +for quotes and comments +inside those ifdefs. +One specifies ignored ifdefs with +.Fl iD Ns Ar sym +and +.Fl iU Ns Ar sym +similar to +.Fl D Ns Ar sym +and +.Fl U Ns Ar sym +above. +.El +.Pp +.Nm Unifdef +copies its output to +.Em stdout +and will take its input from +.Em stdin +if no +.Ar file +argument is given. +.Pp +.Nm Unifdef +works nicely with the +.Fl D Ns Ar sym +option added to +.Xr diff 1 +as of the 4.1 Berkeley Software Distribution. +.Sh SEE ALSO +.Xr diff 1 +.Sh DIAGNOSTICS +Inappropriate else or endif. +.br +Premature +.Tn EOF +with line numbers of the unterminated #ifdefs. +.Pp +Exit status is 0 if output is exact copy of input, 1 if not, 2 if trouble. +.Sh BUGS +Should try to deal with ``#if'' lines. +.Pp +Doesn't work correctly if input contains null characters. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/unifdef/unifdef.c b/usr.bin/unifdef/unifdef.c new file mode 100644 index 0000000..0fe80fc --- /dev/null +++ b/usr.bin/unifdef/unifdef.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Dave Yost. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1985, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)unifdef.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * unifdef - remove ifdef'ed lines + * + * Warning: will not work correctly if input contains null characters. + * + * Wishlist: + * provide an option which will append the name of the + * appropriate symbol after #else's and #endif's + * provide an option which will check symbols after + * #else's and #endif's to see that they match their + * corresponding #ifdef or #ifndef + */ + +#include +#include + +#define BSS +FILE *input; +#ifndef YES +#define YES 1 +#define NO 0 +#endif/*YES */ +typedef int Bool; + +char *progname BSS; +char *filename BSS; +char text BSS; /* -t option in effect: this is a text file */ +char lnblank BSS; /* -l option in effect: blank deleted lines */ +char complement BSS; /* -c option in effect: complement the operation */ + +#define MAXSYMS 100 +char *symname[MAXSYMS] BSS; /* symbol name */ +char true[MAXSYMS] BSS; /* -Dsym */ +char ignore[MAXSYMS] BSS; /* -iDsym or -iUsym */ +char insym[MAXSYMS] BSS; /* state: false, inactive, true */ +#define SYM_INACTIVE 0 /* symbol is currently inactive */ +#define SYM_FALSE 1 /* symbol is currently false */ +#define SYM_TRUE 2 /* symbol is currently true */ + +char nsyms BSS; +char incomment BSS; /* inside C comment */ + +#define QUOTE_NONE 0 +#define QUOTE_SINGLE 1 +#define QUOTE_DOUBLE 2 +char inquote BSS; /* inside single or double quotes */ + +int exitstat BSS; +char *skipcomment (); +char *skipquote (); + +main (argc, argv) +int argc; +char **argv; +{ + char **curarg; + register char *cp; + register char *cp1; + char ignorethis; + + progname = argv[0][0] ? argv[0] : "unifdef"; + + for (curarg = &argv[1]; --argc > 0; curarg++) { + if (*(cp1 = cp = *curarg) != '-') + break; + if (*++cp1 == 'i') { + ignorethis = YES; + cp1++; + } else + ignorethis = NO; + if ( ( *cp1 == 'D' + || *cp1 == 'U' + ) + && cp1[1] != '\0' + ) { + register int symind; + + if ((symind = findsym (&cp1[1])) < 0) { + if (nsyms >= MAXSYMS) { + prname (); + fprintf (stderr, "too many symbols.\n"); + exit (2); + } + symind = nsyms++; + symname[symind] = &cp1[1]; + insym[symind] = SYM_INACTIVE; + } + ignore[symind] = ignorethis; + true[symind] = *cp1 == 'D' ? YES : NO; + } else if (ignorethis) + goto unrec; + else if (strcmp (&cp[1], "t") == 0) + text = YES; + else if (strcmp (&cp[1], "l") == 0) + lnblank = YES; + else if (strcmp (&cp[1], "c") == 0) + complement = YES; + else { + unrec: + prname (); + fprintf (stderr, "unrecognized option: %s\n", cp); + goto usage; + } + } + if (nsyms == 0) { + usage: + fprintf (stderr, "\ +Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]]... [file]\n\ + At least one arg from [-D -U -iD -iU] is required\n", progname); + exit (2); + } + + if (argc > 1) { + prname (); + fprintf (stderr, "can only do one file.\n"); + } else if (argc == 1) { + filename = *curarg; + if ((input = fopen (filename, "r")) != NULL) { + pfile(); + (void) fclose (input); + } else { + prname (); + fprintf (stderr, "can't open "); + perror(*curarg); + } + } else { + filename = "[stdin]"; + input = stdin; + pfile(); + } + + (void) fflush (stdout); + exit (exitstat); +} + +/* types of input lines: */ +typedef int Linetype; +#define LT_PLAIN 0 /* ordinary line */ +#define LT_TRUE 1 /* a true #ifdef of a symbol known to us */ +#define LT_FALSE 2 /* a false #ifdef of a symbol known to us */ +#define LT_OTHER 3 /* an #ifdef of a symbol not known to us */ +#define LT_IF 4 /* an #ifdef of a symbol not known to us */ +#define LT_ELSE 5 /* #else */ +#define LT_ENDIF 6 /* #endif */ +#define LT_LEOF 7 /* end of file */ +extern Linetype checkline (); + +typedef int Reject_level; +Reject_level reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */ +#define REJ_NO 0 +#define REJ_IGNORE 1 +#define REJ_YES 2 + +int linenum BSS; /* current line number */ +int stqcline BSS; /* start of current coment or quote */ +char *errs[] = { +#define NO_ERR 0 + "", +#define END_ERR 1 + "", +#define ELSE_ERR 2 + "Inappropriate else", +#define ENDIF_ERR 3 + "Inappropriate endif", +#define IEOF_ERR 4 + "Premature EOF in ifdef", +#define CEOF_ERR 5 + "Premature EOF in comment", +#define Q1EOF_ERR 6 + "Premature EOF in quoted character", +#define Q2EOF_ERR 7 + "Premature EOF in quoted string" +}; + +/* States for inif arg to doif */ +#define IN_NONE 0 +#define IN_IF 1 +#define IN_ELSE 2 + +pfile () +{ + reject = REJ_NO; + (void) doif (-1, IN_NONE, reject, 0); + return; +} + +int +doif (thissym, inif, prevreject, depth) +register int thissym; /* index of the symbol who was last ifdef'ed */ +int inif; /* YES or NO we are inside an ifdef */ +Reject_level prevreject;/* previous value of reject */ +int depth; /* depth of ifdef's */ +{ + register Linetype lineval; + register Reject_level thisreject; + int doret; /* tmp return value of doif */ + int cursym; /* index of the symbol returned by checkline */ + int stline; /* line number when called this time */ + + stline = linenum; + for (;;) { + switch (lineval = checkline (&cursym)) { + case LT_PLAIN: + flushline (YES); + break; + + case LT_TRUE: + case LT_FALSE: + thisreject = reject; + if (lineval == LT_TRUE) + insym[cursym] = SYM_TRUE; + else { + if (reject != REJ_YES) + reject = ignore[cursym] ? REJ_IGNORE : REJ_YES; + insym[cursym] = SYM_FALSE; + } + if (ignore[cursym]) + flushline (YES); + else { + exitstat = 1; + flushline (NO); + } + if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR) + return error (doret, stline, depth); + break; + + case LT_IF: + case LT_OTHER: + flushline (YES); + if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR) + return error (doret, stline, depth); + break; + + case LT_ELSE: + if (inif != IN_IF) + return error (ELSE_ERR, linenum, depth); + inif = IN_ELSE; + if (thissym >= 0) { + if (insym[thissym] == SYM_TRUE) { + reject = ignore[thissym] ? REJ_IGNORE : REJ_YES; + insym[thissym] = SYM_FALSE; + } else { /* (insym[thissym] == SYM_FALSE) */ + reject = prevreject; + insym[thissym] = SYM_TRUE; + } + if (!ignore[thissym]) { + flushline (NO); + break; + } + } + flushline (YES); + break; + + case LT_ENDIF: + if (inif == IN_NONE) + return error (ENDIF_ERR, linenum, depth); + if (thissym >= 0) { + insym[thissym] = SYM_INACTIVE; + reject = prevreject; + if (!ignore[thissym]) { + flushline (NO); + return NO_ERR; + } + } + flushline (YES); + return NO_ERR; + + case LT_LEOF: { + int err; + err = incomment + ? CEOF_ERR + : inquote == QUOTE_SINGLE + ? Q1EOF_ERR + : inquote == QUOTE_DOUBLE + ? Q2EOF_ERR + : NO_ERR; + if (inif != IN_NONE) { + if (err != NO_ERR) + (void) error (err, stqcline, depth); + return error (IEOF_ERR, stline, depth); + } else if (err != NO_ERR) + return error (err, stqcline, depth); + else + return NO_ERR; + } + } + } +} + +#define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_') + +#define MAXLINE 256 +char tline[MAXLINE] BSS; + +Linetype +checkline (cursym) +int *cursym; /* if LT_TRUE or LT_FALSE returned, set this to sym index */ +{ + register char *cp; + register char *symp; + char *scp; + Linetype retval; +# define KWSIZE 8 + char keyword[KWSIZE]; + + linenum++; + if (getlin (tline, sizeof tline, input, NO) == EOF) + return LT_LEOF; + + retval = LT_PLAIN; + if ( *(cp = tline) != '#' + || incomment + || inquote == QUOTE_SINGLE + || inquote == QUOTE_DOUBLE + ) + goto eol; + + cp = skipcomment (++cp); + symp = keyword; + while (!endsym (*cp)) { + *symp = *cp++; + if (++symp >= &keyword[KWSIZE]) + goto eol; + } + *symp = '\0'; + + if (strcmp (keyword, "ifdef") == 0) { + retval = YES; + goto ifdef; + } else if (strcmp (keyword, "ifndef") == 0) { + retval = NO; + ifdef: + scp = cp = skipcomment (++cp); + if (incomment) { + retval = LT_PLAIN; + goto eol; + } + { + int symind; + + if ((symind = findsym (scp)) >= 0) + retval = (retval ^ true[*cursym = symind]) + ? LT_FALSE : LT_TRUE; + else + retval = LT_OTHER; + } + } else if (strcmp (keyword, "if") == 0) + retval = LT_IF; + else if (strcmp (keyword, "else") == 0) + retval = LT_ELSE; + else if (strcmp (keyword, "endif") == 0) + retval = LT_ENDIF; + + eol: + if (!text && reject != REJ_IGNORE) + for (; *cp; ) { + if (incomment) + cp = skipcomment (cp); + else if (inquote == QUOTE_SINGLE) + cp = skipquote (cp, QUOTE_SINGLE); + else if (inquote == QUOTE_DOUBLE) + cp = skipquote (cp, QUOTE_DOUBLE); + else if (*cp == '/' && cp[1] == '*') + cp = skipcomment (cp); + else if (*cp == '\'') + cp = skipquote (cp, QUOTE_SINGLE); + else if (*cp == '"') + cp = skipquote (cp, QUOTE_DOUBLE); + else + cp++; + } + return retval; +} + +/* + * Skip over comments and stop at the next charaacter + * position that is not whitespace. + */ +char * +skipcomment (cp) +register char *cp; +{ + if (incomment) + goto inside; + for (;; cp++) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (text) + return cp; + if ( cp[0] != '/' + || cp[1] != '*' + ) + return cp; + cp += 2; + if (!incomment) { + incomment = YES; + stqcline = linenum; + } + inside: + for (;;) { + for (; *cp != '*'; cp++) + if (*cp == '\0') + return cp; + if (*++cp == '/') { + incomment = NO; + break; + } + } + } +} + +/* + * Skip over a quoted string or character and stop at the next charaacter + * position that is not whitespace. + */ +char * +skipquote (cp, type) +register char *cp; +register int type; +{ + register char qchar; + + qchar = type == QUOTE_SINGLE ? '\'' : '"'; + + if (inquote == type) + goto inside; + for (;; cp++) { + if (*cp != qchar) + return cp; + cp++; + inquote = type; + stqcline = linenum; + inside: + for (; ; cp++) { + if (*cp == qchar) + break; + if ( *cp == '\0' + || *cp == '\\' && *++cp == '\0' + ) + return cp; + } + inquote = QUOTE_NONE; + } +} + +/* + * findsym - look for the symbol in the symbol table. + * if found, return symbol table index, + * else return -1. + */ +int +findsym (str) +char *str; +{ + register char *cp; + register char *symp; + register int symind; + register char chr; + + for (symind = 0; symind < nsyms; ++symind) { + if (insym[symind] == SYM_INACTIVE) { + for ( symp = symname[symind], cp = str + ; *symp && *cp == *symp + ; cp++, symp++ + ) + continue; + chr = *cp; + if (*symp == '\0' && endsym (chr)) + return symind; + } + } + return -1; +} + +/* + * getlin - expands tabs if asked for + * and (if compiled in) treats form-feed as an end-of-line + */ +int +getlin (line, maxline, inp, expandtabs) +register char *line; +int maxline; +FILE *inp; +int expandtabs; +{ + int tmp; + register int num; + register int chr; +#ifdef FFSPECIAL + static char havechar = NO; /* have leftover char from last time */ + static char svchar BSS; +#endif/*FFSPECIAL */ + + num = 0; +#ifdef FFSPECIAL + if (havechar) { + havechar = NO; + chr = svchar; + goto ent; + } +#endif/*FFSPECIAL */ + while (num + 8 < maxline) { /* leave room for tab */ + chr = getc (inp); + if (isprint (chr)) { +#ifdef FFSPECIAL + ent: +#endif/*FFSPECIAL */ + *line++ = chr; + num++; + } else + switch (chr) { + case EOF: + return EOF; + + case '\t': + if (expandtabs) { + num += tmp = 8 - (num & 7); + do + *line++ = ' '; + while (--tmp); + break; + } + default: + *line++ = chr; + num++; + break; + + case '\n': + *line = '\n'; + num++; + goto end; + +#ifdef FFSPECIAL + case '\f': + if (++num == 1) + *line = '\f'; + else { + *line = '\n'; + havechar = YES; + svchar = chr; + } + goto end; +#endif/*FFSPECIAL */ + } + } + end: + *++line = '\0'; + return num; +} + +flushline (keep) +Bool keep; +{ + if ((keep && reject != REJ_YES) ^ complement) { + register char *line = tline; + register FILE *out = stdout; + register char chr; + + while (chr = *line++) + putc (chr, out); + } else if (lnblank) + putc ('\n', stdout); + return; +} + +prname () +{ + fprintf (stderr, "%s: ", progname); + return; +} + +int +error (err, line, depth) +int err; /* type of error & index into error string array */ +int line; /* line number */ +int depth; /* how many ifdefs we are inside */ +{ + if (err == END_ERR) + return err; + + prname (); + +#ifndef TESTING + fprintf (stderr, "Error in %s line %d: %s.\n", filename, line, errs[err]); +#else/* TESTING */ + fprintf (stderr, "Error in %s line %d: %s. ", filename, line, errs[err]); + fprintf (stderr, "ifdef depth: %d\n", depth); +#endif/*TESTING */ + + exitstat = 2; + return depth > 1 ? IEOF_ERR : END_ERR; +} diff --git a/usr.bin/uniq/Makefile b/usr.bin/uniq/Makefile new file mode 100644 index 0000000..fa0db8b --- /dev/null +++ b/usr.bin/uniq/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uniq + +.include diff --git a/usr.bin/uniq/uniq.1 b/usr.bin/uniq/uniq.1 new file mode 100644 index 0000000..0898e0e --- /dev/null +++ b/usr.bin/uniq/uniq.1 @@ -0,0 +1,130 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)uniq.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UNIQ 1 +.Os +.Sh NAME +.Nm uniq +.Nd report or filter out repeated lines in a file +.Sh SYNOPSIS +.Nm uniq +.Op Fl c | Fl d | Fl u +.Op Fl f Ar fields +.Op Fl s Ar chars +.Oo +.Ar input_file +.Op Ar output_file +.Oc +.Sh DESCRIPTION +The +.Nm uniq +utility reads the standard input comparing adjacent lines, and writes +a copy of each unique input line to the standard output. +The second and succeeding copies of identical adjacent input lines are +not written. +Repeated lines in the input will not be detected if they are not adjacent, +so it may be necessary to sort the files first. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl c +Precede each output line with the count of the number of times the line +occurred in the input, followed by a single space. +.It Fl d +Don't output lines that are not repeated in the input. +.It Fl f Ar fields +Ignore the first +.Ar fields +in each input line when doing comparisons. +A field is a string of non-blank characters separated from adjacent fields +by blanks. +Field numbers are one based, i.e. the first field is field one. +.It Fl s Ar chars +Ignore the first +.Ar chars +characters in each input line when doing comparisons. +If specified in conjunction with the +.Fl f +option, the first +.Ar chars +characters after the first +.Ar fields +fields will be ignored. +Character numbers are one based, i.e. the first character is character one. +.It Fl u +Don't output lines that are repeated in the input. +.\".It Fl Ns Ar n +.\"(Deprecated; replaced by +.\".Fl f ) . +.\"Ignore the first n +.\"fields on each input line when doing comparisons, +.\"where n is a number. +.\"A field is a string of non-blank +.\"characters separated from adjacent fields +.\"by blanks. +.\".It Cm \&\(pl Ns Ar n +.\"(Deprecated; replaced by +.\".Fl s ) . +.\"Ignore the first +.\".Ar m +.\"characters when doing comparisons, where +.\".Ar m +.\"is a +.\"number. +.El +.Pp +If additional arguments are specified on the command line, the first +such argument is used as the name of an input file, the second is used +as the name of an output file. +.Pp +The +.Nm uniq +utility exits 0 on success, and >0 if an error occurs. +.Sh COMPATIBILITY +The historic +.Cm \&\(pl Ns Ar number +and +.Fl Ns Ar number +options have been deprecated but are still supported in this implementation. +.Sh SEE ALSO +.Xr sort 1 +.Sh STANDARDS +The +.Nm uniq +utility is expected to be +.St -p1003.2 +compatible. diff --git a/usr.bin/uniq/uniq.c b/usr.bin/uniq/uniq.c new file mode 100644 index 0000000..e84f82e --- /dev/null +++ b/usr.bin/uniq/uniq.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Case Larsen. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uniq.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#define MAXLINELEN (8 * 1024) + +int cflag, dflag, uflag; +int numchars, numfields, repeats; + +void err __P((const char *, ...)); +FILE *file __P((char *, char *)); +void show __P((FILE *, char *)); +char *skip __P((char *)); +void obsolete __P((char *[])); +void usage __P((void)); + +int +main (argc, argv) + int argc; + char *argv[]; +{ + register char *t1, *t2; + FILE *ifp, *ofp; + int ch; + char *prevline, *thisline, *p; + + obsolete(argv); + while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF) + switch (ch) { + case '-': + --optind; + goto done; + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'f': + numfields = strtol(optarg, &p, 10); + if (numfields < 0 || *p) + err("illegal field skip value: %s", optarg); + break; + case 's': + numchars = strtol(optarg, &p, 10); + if (numchars < 0 || *p) + err("illegal character skip value: %s", optarg); + break; + case 'u': + uflag = 1; + break; + case '?': + default: + usage(); + } + +done: argc -= optind; + argv +=optind; + + /* If no flags are set, default is -d -u. */ + if (cflag) { + if (dflag || uflag) + usage(); + } else if (!dflag && !uflag) + dflag = uflag = 1; + + switch(argc) { + case 0: + ifp = stdin; + ofp = stdout; + break; + case 1: + ifp = file(argv[0], "r"); + ofp = stdout; + break; + case 2: + ifp = file(argv[0], "r"); + ofp = file(argv[1], "w"); + break; + default: + usage(); + } + + prevline = malloc(MAXLINELEN); + thisline = malloc(MAXLINELEN); + if (prevline == NULL || thisline == NULL) + err("%s", strerror(errno)); + + if (fgets(prevline, MAXLINELEN, ifp) == NULL) + exit(0); + + while (fgets(thisline, MAXLINELEN, ifp)) { + /* If requested get the chosen fields + character offsets. */ + if (numfields || numchars) { + t1 = skip(thisline); + t2 = skip(prevline); + } else { + t1 = thisline; + t2 = prevline; + } + + /* If different, print; set previous to new value. */ + if (strcmp(t1, t2)) { + show(ofp, prevline); + t1 = prevline; + prevline = thisline; + thisline = t1; + repeats = 0; + } else + ++repeats; + } + show(ofp, prevline); + exit(0); +} + +/* + * show -- + * Output a line depending on the flags and number of repetitions + * of the line. + */ +void +show(ofp, str) + FILE *ofp; + char *str; +{ + if (cflag) + (void)fprintf(ofp, "%4d %s", repeats + 1, str); + if (dflag && repeats || uflag && !repeats) + (void)fprintf(ofp, "%s", str); +} + +char * +skip(str) + register char *str; +{ + register int infield, nchars, nfields; + + for (nfields = numfields, infield = 0; nfields && *str; ++str) + if (isspace(*str)) { + if (infield) { + infield = 0; + --nfields; + } + } else if (!infield) + infield = 1; + for (nchars = numchars; nchars-- && *str; ++str); + return(str); +} + +FILE * +file(name, mode) + char *name, *mode; +{ + FILE *fp; + + if ((fp = fopen(name, mode)) == NULL) + err("%s: %s", name, strerror(errno)); + return(fp); +} + +void +obsolete(argv) + char *argv[]; +{ + int len; + char *ap, *p, *start; + + while (ap = *++argv) { + /* Return if "--" or not an option of any form. */ + if (ap[0] != '-') { + if (ap[0] != '+') + return; + } else if (ap[1] == '-') + return; + if (!isdigit(ap[1])) + continue; + /* + * Digit signifies an old-style option. Malloc space for dash, + * new option and argument. + */ + len = strlen(ap); + if ((start = p = malloc(len + 3)) == NULL) + err("%s", strerror(errno)); + *p++ = '-'; + *p++ = ap[0] == '+' ? 's' : 'f'; + (void)strcpy(p, ap + 1); + *argv = start; + } +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "uniq: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/unvis/Makefile b/usr.bin/unvis/Makefile new file mode 100644 index 0000000..a6807ff --- /dev/null +++ b/usr.bin/unvis/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= unvis + +.include diff --git a/usr.bin/unvis/unvis.1 b/usr.bin/unvis/unvis.1 new file mode 100644 index 0000000..5d531af --- /dev/null +++ b/usr.bin/unvis/unvis.1 @@ -0,0 +1,57 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)unvis.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UNVIS 1 +.Os BSD 4.4 +.Sh NAME +.Nm unvis +.Nd "revert a visual representation of data back to original form" +.Sh SYNOPSIS +.Nm unvis +.Op Ar file ... +.Sh DESCRIPTION +.Nm Unvis +is the inverse function of +.Xr vis 1 . +It reverts +a visual representation of data back to its original form on standard output. +.Sh SEE ALSO +.Xr vis 1 , +.Xr unvis 3 , +.Xr vis 3 +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/unvis/unvis.c b/usr.bin/unvis/unvis.c new file mode 100644 index 0000000..82cad81 --- /dev/null +++ b/usr.bin/unvis/unvis.c @@ -0,0 +1,147 @@ +/*- + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +char *Program; +#define usage() fprintf(stderr, "usage: %s %s\n", Program, USAGE) +#define USAGE "[file...]" + +main(argc, argv) + char *argv[]; +{ + FILE *fp; + extern char *optarg; + extern int optind; + int ch; + + Program = argv[0]; + while ((ch = getopt(argc, argv, "")) != EOF) + switch((char)ch) { + case '?': + default: + usage(); + exit(1); + } + argc -= optind; + argv += optind; + + if (*argv) + while (*argv) { + if ((fp=fopen(*argv, "r")) != NULL) + process(fp, *argv); + else + syserror("%s", *argv); + argv++; + } + else + process(stdin, ""); + exit(0); +} + +process(fp, filename) + FILE *fp; + char *filename; +{ + register int offset = 0, c, ret; + int state = 0; + char outc; + + while ((c = getc(fp)) != EOF) { + offset++; + again: + switch(ret = unvis(&outc, (char)c, &state, 0)) { + case UNVIS_VALID: + putchar(outc); + break; + case UNVIS_VALIDPUSH: + putchar(outc); + goto again; + case UNVIS_SYNBAD: + error("%s: offset: %d: can't decode", filename, offset); + state = 0; + break; + case 0: + case UNVIS_NOCHAR: + break; + default: + error("bad return value (%d), can't happen", ret); + exit(1); + } + } + if (unvis(&outc, (char)0, &state, UNVIS_END) == UNVIS_VALID) + putchar(outc); +} + +#include + +error(va_alist) + va_dcl +{ + char *fmt; + va_list ap; + extern errno; + + fprintf(stderr, "%s: ", Program); + va_start(ap); + fmt = va_arg(ap, char *); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +syserror(va_alist) + va_dcl +{ + char *fmt; + va_list ap; + extern errno; + + fprintf(stderr, "%s: ", Program); + va_start(ap); + fmt = va_arg(ap, char *); + (void) vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); +} diff --git a/usr.bin/users/Makefile b/usr.bin/users/Makefile new file mode 100644 index 0000000..d0825d0 --- /dev/null +++ b/usr.bin/users/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= users + +.include diff --git a/usr.bin/users/users.1 b/usr.bin/users/users.1 new file mode 100644 index 0000000..0dd1b0f --- /dev/null +++ b/usr.bin/users/users.1 @@ -0,0 +1,59 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)users.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt USERS 1 +.Os BSD 3 +.Sh NAME +.Nm users +.Nd list current users +.Sh SYNOPSIS +.Nm users +.Sh DESCRIPTION +.Nm Users +lists the login names of the users currently on the system, +in sorted order, space separated, on a single line. +.Sh FILES +.Bl -tag -width /etc/utmp +.It Pa /etc/utmp +.El +.Sh SEE ALSO +.Xr finger 1 , +.Xr last 1 , +.Xr who 1 , +.Xr utmp 5 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/users/users.c b/usr.bin/users/users.c new file mode 100644 index 0000000..11571f2 --- /dev/null +++ b/usr.bin/users/users.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1980, 1987, 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 copyright[] = +"@(#) Copyright (c) 1980, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)users.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include + +#define MAXUSERS 200 + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + register int cnt, ncnt; + struct utmp utmp; + char names[MAXUSERS][UT_NAMESIZE]; + int ch, scmp(); + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + (void)fprintf(stderr, "usage: users\n"); + exit(1); + } + argc -= optind; + argv += optind; + + if (!freopen(_PATH_UTMP, "r", stdin)) { + (void)fprintf(stderr, "users: can't open %s.\n", _PATH_UTMP); + exit(1); + } + for (ncnt = 0; + fread((char *)&utmp, sizeof(utmp), 1, stdin) == 1;) + if (*utmp.ut_name) { + if (ncnt == MAXUSERS) { + (void)fprintf(stderr, + "users: too many users.\n"); + break; + } + (void)strncpy(names[ncnt], utmp.ut_name, UT_NAMESIZE); + ++ncnt; + } + + if (ncnt) { + qsort(names, ncnt, UT_NAMESIZE, scmp); + (void)printf("%.*s", UT_NAMESIZE, names[0]); + for (cnt = 1; cnt < ncnt; ++cnt) + if (strncmp(names[cnt], names[cnt - 1], UT_NAMESIZE)) + (void)printf(" %.*s", UT_NAMESIZE, names[cnt]); + (void)printf("\n"); + } + exit(0); +} + +scmp(p, q) + char *p, *q; +{ + return(strncmp(p, q, UT_NAMESIZE)); +} diff --git a/usr.bin/uucp/acucntrl/Makefile b/usr.bin/uucp/acucntrl/Makefile new file mode 100644 index 0000000..85bbfe4 --- /dev/null +++ b/usr.bin/uucp/acucntrl/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= acucntrl +CFLAGS+=-I${.CURDIR}/../includes +BINDIR= ${LIBDIR} +BINOWN= root +BINMODE=6550 +MAN8= acucntrl.0 + +.include diff --git a/usr.bin/uucp/acucntrl/acucntrl.8 b/usr.bin/uucp/acucntrl/acucntrl.8 new file mode 100644 index 0000000..57ce495 --- /dev/null +++ b/usr.bin/uucp/acucntrl/acucntrl.8 @@ -0,0 +1,164 @@ +.\" Copyright (c) 1985, 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. +.\" +.\" @(#)acucntrl.8 8.2 (Berkeley) 12/11/93 +.\" +.TH ACUCNTRL 8 "December 11, 1993" +.UC 6 +.SH NAME +acucntrl \- turn around tty line between dialin and dialout +.SH SYNOPSIS +.B /usr/lib/uucp/acucntrl +keyword ttyline +.SH DESCRIPTION +.PP +.I Acucntrl +turns around the terminal line, +enabling it to be used for both dialin and dialout. +On dialin a terminal line is assumed to have modem control enabled and a getty +process in existence waiting for logins. On dialout modem control is disabled +and there is no getty process. +.PP +This program must be run setuid to root. +.PP +.I keyword +is chosen from the list: +.I disable +or +.IR dialout , +to condition a line for dialout; +and +.I enable +or +.IR dialin , +to condition a line for dialin. +.PP +When the line is conditioned for dialing out, the login name of the real uid +of the process is placed in /etc/utmp in capitals. +This declares that the line is in use and acts as an additional locking +mechanism. +.I Acucntrl +will refuse to act if the /etc/utmp entry for the line is not null, +is not the the user's login name (capitalized or not), +and if the process is not running as the superuser. +The last condition is to allow the superuser to clear the state of the line. +.PP +Turning modem control on or off is handled by poking into /dev/kmem. +It is currently implemented for dz, dh, and dmf lines. +.PP +Under 4.2 BSD the program will also refuse to disable a line if carrier is +sensed on it. This is to avoid the dead period where someone has just dialed +in and made the connection but has not yet logged in. +.PP +.I Ttyline +can be either of the form tty* or /dev/tty*. +Enabling/disabling a line whose name does not begin with ttyd? is prohibited +unless the real uid of the process is 0 or if the login name corresponding to +the real uid is uucp. This is a security precaution. +.PP +Steps taken when disabling +.RI ( i . e . +setup for dialing out) +.IP 1) +check input arguments +.IP 2) +look in /etc/utmp to check that the line is not in use by another user +.IP 3) +disable modem control on line +.IP 4) +check for carrier on device +.IP 5) +change owner of device to real uid +.IP 6) +edit /etc/ttys, changing the first character of the appropriate line to 0 +.IP 7) +send a hangup to process 1 to poke init to disable getty +.IP 8) +post uid name in capitals in /etc/utmp to let world know device has been grabbed +.IP 9) +make sure that DTR is on +.PP +Steps taken when enabling +.RI ( i . e . +setup for dialing in) +.IP 1) +check input arguments +.IP 2) +look in /etc/utmp to check that the line is not in use by another user +.IP 3) +make sure modem control on line is disabled +.IP 4) +turn off DTR to make sure line is hung up +.IP 5) +condition line: clear exclusive use and set hangup on close modes +.IP 6) +turn on modem control +.IP 7) +edit /etc/ttys, changing the first character of the appropriate line to 1 +.IP 8) +send a hangup to process 1 to poke init to enable getty +.IP 9) +clear uid name for /etc/utmp +.SH HISTORY +.PP +First written by Allan Wilkes (fisher!allan) +.PP +Modified June 8,1983 by W.Sebok (astrovax!wls) to poke the kernel rather +than use a kernel hack to turn on/off modem control, using a subroutine +stolen from a program written by Tsutomu Shimomura {astrovax,escher}!tsutomu +.PP +Worked over many times by W.Sebok +.RI ( i . e . +hacked to death) +.SH FILES +/dev/kmem, /vmunix, /etc/ttys, /etc/utmp, /dev/tty* +.SH BUGS +.PP +Sensing carrier requires the 4.2 BSD TIOCMGET ioctl call. Unfortunately this +ioctl is not implemented in the vanilla 4.2 BSD dh driver even though the +dz and dmf drivers use an emulation of the DH11's modem control bits. This +has been fixed here. +.PP +Some time (currently 2 seconds) is required between disabling modem control +and opening the device. This is probably because of a race with getty whose +open is finally being allowed to complete. This time interval may not be +enough on a loaded system. Because of this problem and the above problem with +the dh driver there is deliberately no error message given when the TIOCMGET +ioctl fails. +.PP +Previously there were similar synchronization problems with the init process. +When dialins are disabled the capitalized name of the process cannot be posted +into /etc/utmp until init has finished clearing /etc/utmp. However one does +not know how long that will take, and, on a loaded system, it can take quite +a while. This was solved by the strategy of 1) posting the name, 2) poking +init, 3) going into a loop where the process repeatedly waits a second and +checks whether the entry has been cleared from /etc/utmp, and 4) posting the +name again. diff --git a/usr.bin/uucp/acucntrl/acucntrl.c b/usr.bin/uucp/acucntrl/acucntrl.c new file mode 100644 index 0000000..deba6ba --- /dev/null +++ b/usr.bin/uucp/acucntrl/acucntrl.c @@ -0,0 +1,814 @@ +/*- + * Copyright (c) 1985, 1986, 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 copyright[] = +"@(#) Copyright (c) 1985, 1986, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)acucntrl.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* acucntrl - turn around tty line between dialin and dialout + * + * Usage: acucntrl {enable,disable} /dev/ttydX + * + * History: + * First written by Allan Wilkes (fisher!allan) + * + * Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather + * than use kernel hack to turn on/off modem control, using subroutine + * stolen from program written by Tsutomu Shimomura + * {astrovax,escher}!tsutomu + * + * Worked over many times by W.Sebok (i.e. hacked to death) + * + * Operation: + * disable (i.e. setup for dialing out) + * (1) check input arguments + * (2) look in _PATH_UTMP to check that the line is not in use by another + * (3) disable modem control on terminal + * (4) check for carrier on device + * (5) change owner of device to real id + * (6) edit _PATH_TTYS, changing the first character of the appropriate + * line to 0 + * (7) send a hangup to process 1 to poke init to disable getty + * (8) post uid name in capitals in _PATH_UTMP to let world know device + * has been grabbed + * (9) make sure that DTR is on + * + * enable (i.e.) restore for dialin + * (1) check input arguments + * (2) look in _PATH_UTMP to check that the line is not in use by another + * (3) make sure modem control on terminal is disabled + * (4) turn off DTR to make sure line is hung up + * (5) condition line: clear exclusive use and set hangup on close modes + * (6) turn on modem control + * (7) edit _PATH_TTYS, changing the first character of the appropriate + * line to 1 + * (8) send a hangup to process 1 to poke init to enable getty + * (9) clear uid name for _PATH_UTMP + */ + +/* #define SENSECARRIER */ + +#include "uucp.h" +#ifdef DIALINOUT +#include +#include +#include +#ifdef vax +#ifdef BSD4_2 +#include +#else +#include +#endif +#endif /* vax */ +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +#define NDZLINE 8 /* lines/dz */ +#define NDHLINE 16 /* lines/dh */ +#define NDMFLINE 8 /* lines/dmf */ + +#define DZ11 1 +#define DH11 2 +#define DMF 3 + +#define NLVALUE(val) (nl[val].n_value) + +struct nlist nl[] = { +#define CDEVSW 0 + { "_cdevsw" }, + +#define DZOPEN 1 + { "_dzopen" }, +#define DZINFO 2 + { "_dzinfo" }, +#define NDZ11 3 + { "_dz_cnt" }, +#define DZSCAR 4 + { "_dzsoftCAR" }, + +#define DHOPEN 5 + { "_dhopen" }, +#define DHINFO 6 + { "_dhinfo" }, +#define NDH11 7 + { "_ndh11" }, +#define DHSCAR 8 + { "_dhsoftCAR" }, + +#define DMFOPEN 9 + { "_dmfopen" }, +#define DMFINFO 10 + { "_dmfinfo" }, +#define NDMF 11 + { "_ndmf" }, +#define DMFSCAR 12 + { "_dmfsoftCAR" }, + + { "\0" } +}; + +#define ENABLE 1 +#define DISABLE 0 + +char Etcttys[] = _PATH_TTYS; +#ifdef BSD4_3 +FILE *ttysfile, *nttysfile; +char NEtcttys[] = _PATH_NEWTTYS; +extern long ftell(); +#endif BSD4_3 +char Devhome[] = _PATH_DEV; + +char usage[] = "Usage: acucntrl {dis|en}able ttydX\n"; + +struct utmp utmp; +char resettty, resetmodem; +int etcutmp; +off_t utmploc; +off_t ttyslnbeg; +extern int errno; +extern char *sys_errlist[]; +off_t lseek(); + +#define NAMSIZ sizeof(utmp.ut_name) +#define LINSIZ sizeof(utmp.ut_line) + +main(argc, argv) +int argc; char *argv[]; +{ + register char *p; + register int i; + char uname[NAMSIZ], Uname[NAMSIZ]; + int enable ; + char *device; + int devfile; + int uid, gid; + struct passwd *getpwuid(); + char *rindex(); + + /* check input arguments */ + if (argc!=3 && argc != 4) { + fprintf(stderr, usage); + exit(1); + } + + /* interpret command type */ + if (prefix(argv[1], "disable") || strcmp(argv[1], "dialout")==0) + enable = 0; + else if (prefix(argv[1], "enable") || strcmp(argv[1], "dialin")==0) + enable = 1; + else { + fprintf(stderr, usage); + exit(1); + } + + device = rindex(argv[2], '/'); + device = (device == NULL) ? argv[2]: device+1; + + opnttys(device); + +#ifdef vax + /* Get nlist info */ + nlist(_PATH_UNIX, nl); +#endif vax + + /* Chdir to /dev */ + if(chdir(Devhome) < 0) { + fprintf(stderr, "Cannot chdir to %s: %s\r\n", + Devhome, sys_errlist[errno]); + exit(1); + } + + /* Get uid information */ + uid = getuid(); + gid = getgid(); + + p = getpwuid(uid)->pw_name; + if (p==NULL) { + fprintf(stderr, "cannot get uid name\n"); + exit(1); + } + + if (strcmp(p, "uucp") == 0 && argc == 4) + p = argv[3]; + + /* to upper case */ + i = 0; + do { + uname[i] = *p; + Uname[i++] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p; + } while (*p++ && i= 0 ; str++) + if (*str>='a' && *str<='z') + return(0); + return(1); +} + +/* Post name to public */ +post(device, name) +char *device, *name; +{ + (void)time((time_t *)&utmp.ut_time); + strncpy(utmp.ut_line, device, LINSIZ); + strncpy(utmp.ut_name, name, NAMSIZ); + if (lseek(etcutmp, utmploc, 0) < 0) + fprintf(stderr, "on lseek in %s: %s", + _PATH_UTMP, sys_errlist[errno]); + if (write(etcutmp, (char *)&utmp, sizeof(utmp)) < 0) + fprintf(stderr, "on write in %s: %s", + _PATH_UTMP, sys_errlist[errno]); +} + +/* poke process 1 and wait for it to do its thing */ +pokeinit(device, uname, enable) +char *uname, *device; int enable; +{ + struct utmp utmp; + register int i; + + post(device, uname); + + /* poke init */ + if (kill(1, SIGHUP)) { + fprintf(stderr, + "Cannot send hangup to init process: %s\n", + sys_errlist[errno]); + (void)settys(resettty); + (void)setmodem(device, resetmodem); + exit(1); + } + + if (enable) + return; + + /* wait till init has responded, clearing the utmp entry */ + i = 100; + do { + sleep(1); + if (lseek(etcutmp, utmploc, 0) < 0) + fprintf(stderr, "On lseek in %s: %s", + _PATH_UTMP, sys_errlist[errno]); + if (read(etcutmp, (char *)&utmp, sizeof utmp) < 0) + fprintf(stderr, "On read from %s: %s", + _PATH_UTMP, sys_errlist[errno]); + } while (utmp.ut_name[0] != '\0' && --i > 0); +} + +#ifdef BSD4_3 +/* identify terminal line in ttys */ +opnttys(device) +char *device; +{ + register int ndevice; + register char *p; + char *index(); + char linebuf[BUFSIZ]; + + ttysfile = NULL; + do { + if (ttysfile != NULL) { + fclose(ttysfile); + sleep(5); + } + ttysfile = fopen(Etcttys, "r"); + if(ttysfile == NULL) { + fprintf(stderr, "Cannot open %s: %s\n", Etcttys, + sys_errlist[errno]); + exit(1); + } + } while (flock(fileno(ttysfile), LOCK_NB|LOCK_EX) < 0); + nttysfile = fopen(NEtcttys, "w"); + if(nttysfile == NULL) { + fprintf(stderr, "Cannot open %s: %s\n", Etcttys, + sys_errlist[errno]); + exit(1); + } + + ndevice = strlen(device); +#ifndef BRL4_2 + utmploc = sizeof(utmp); +#else BRL4_2 + utmploc = 0; +#endif BRL4_2 + + while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) { + if(strncmp(device, linebuf, ndevice) == 0) + return; + ttyslnbeg += strlen(linebuf); + if (linebuf[0] != '#' && linebuf[0] != '\0') + utmploc += sizeof(utmp); + if (fputs(linebuf, nttysfile) == NULL) { + fprintf(stderr, "On %s write: %s\n", + Etcttys, sys_errlist[errno]); + exit(1); + } + + } + fprintf(stderr, "%s not found in %s\n", device, Etcttys); + exit(1); +} + +/* modify appropriate line in _PATH_TTYS to turn on/off the device */ +settys(enable) +int enable; +{ + register char *cp, *cp2; + char lbuf[BUFSIZ]; + int i; + char c1, c2; + + (void) fseek(ttysfile, ttyslnbeg, 0); + if(fgets(lbuf, BUFSIZ, ttysfile) == NULL) { + fprintf(stderr, "On %s read: %s\n", + Etcttys, sys_errlist[errno]); + exit(1); + } + /* format is now */ + /* ttyd0 std.100 dialup on secure # comment */ + /* except, 2nd item may have embedded spaces inside quotes, Hubert */ + cp = lbuf; + for (i=0;*cp && i<3;i++) { + if (*cp == '"') { + cp++; + while (*cp && *cp != '"') + cp++; + if (*cp != '\0') + cp++; + }else { + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } + while (*cp && (*cp == ' ' || *cp == '\t')) + cp++; + } + if (*cp == '\0') { + fprintf(stderr,"Badly formatted line in %s:\n%s", + _PATH_TTYS, lbuf); + exit(1); + } + c1 = *--cp; + *cp++ = '\0'; + cp2 = cp; + while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + if (*cp == '\0') { + fprintf(stderr,"Badly formatted line in %s:\n%s", + _PATH_TTYS, lbuf); + exit(1); + } + c2 = *cp; + *cp++ = '\0'; + while (*cp && (*cp == ' ' || *cp == '\t')) + cp++; + resettty = strcmp("on", cp2) != 0; + fprintf(nttysfile,"%s%c%s%c%s", lbuf, c1, enable ? "on" : "off", c2, cp); + if (ferror(nttysfile)) { + fprintf(stderr, "On %s fprintf: %s\n", + NEtcttys, sys_errlist[errno]); + exit(1); + } + while(fgets(lbuf, sizeof(lbuf) - 1, ttysfile) != NULL) { + if (fputs(lbuf, nttysfile) == NULL) { + fprintf(stderr, "On %s write: %s\n", + NEtcttys, sys_errlist[errno]); + exit(1); + } + } + + if (enable^resettty) + (void) unlink(NEtcttys); + else { + struct stat statb; + if (stat(Etcttys, &statb) == 0) { + fchmod(fileno(nttysfile) ,statb.st_mode); + fchown(fileno(nttysfile), statb.st_uid, statb.st_gid); + } + (void) rename(NEtcttys, Etcttys); + } + (void) fclose(nttysfile); + (void) fclose(ttysfile); + return enable^resettty; +} + +#else !BSD4_3 + +/* identify terminal line in ttys */ +opnttys(device) +char *device; +{ + register FILE *ttysfile; + register int ndevice, lnsiz; + register char *p; + char *index(); + char linebuf[BUFSIZ]; + + ttysfile = fopen(Etcttys, "r"); + if(ttysfile == NULL) { + fprintf(stderr, "Cannot open %s: %s\n", Etcttys, + sys_errlist[errno]); + exit(1); + } + + ndevice = strlen(device); + ttyslnbeg = 0; + utmploc = 0; + + while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) { + lnsiz = strlen(linebuf); + if ((p = index(linebuf, '\n')) != NULL) + *p = '\0'; + if(strncmp(device, &linebuf[2], ndevice) == 0) { + (void)fclose(ttysfile); +#ifdef sequent + /* Why is the sequent off by one? */ + utmploc += sizeof(utmp); +#endif sequent + return; + } + ttyslnbeg += lnsiz; + utmploc += sizeof(utmp); + } + fprintf(stderr, "%s not found in %s\n", device, Etcttys); + exit(1); +} + +/* modify appropriate line in _PATH_TTYS to turn on/off the device */ +settys(enable) +int enable; +{ + int ittysfil; + char out, in; + + ittysfil = open(Etcttys, 2); + if(ittysfil < 0) { + fprintf(stderr, "Cannot open %s for output: %s\n", + Etcttys, sys_errlist[errno]); + exit(1); + } + (void)lseek(ittysfil, ttyslnbeg, 0); + if(read(ittysfil, &in, 1)<0) { + fprintf(stderr, "On %s write: %s\n", + Etcttys, sys_errlist[errno]); + exit(1); + } + resettty = (in == '1'); + out = enable ? '1' : '0'; + (void)lseek(ittysfil, ttyslnbeg, 0); + if(write(ittysfil, &out, 1)<0) { + fprintf(stderr, "On %s write: %s\n", + Etcttys, sys_errlist[errno]); + exit(1); + } + (void)close(ittysfil); + return(in==out); +} +#endif !BSD4_3 + +#ifdef sequent +setmodem(ttyline, enable) +char *ttyline; int enable; +{ + char *sysbuf[BUFSIZ]; + sprintf(sysbuf,"/etc/ttyconfig /dev/%s -special %s", ttyline, + enable ? "-carrier" : "-nocarrier"); + system(sysbuf); +} +#endif /* sequent */ +#ifdef vax +/* + * Excerpted from (June 8, 1983 W.Sebok) + * > ttymodem.c - enable/disable modem control for tty lines. + * > + * > Knows about DZ11s and DH11/DM11s. + * > 23.3.83 - TS + * > modified to know about DMF's (hasn't been tested) Nov 8, 1984 - WLS + */ + + +setmodem(ttyline, enable) +char *ttyline; int enable; +{ + dev_t dev; + int kmem; + int unit, line, nlines, addr, tflags; + int devtype=0; + char cflags; short sflags; +#ifdef BSD4_2 + int flags; +#else + short flags; +#endif + struct uba_device *ubinfo; + struct stat statb; + struct cdevsw cdevsw; + + if(nl[CDEVSW].n_type == 0) { + fprintf(stderr, "No namelist.\n"); + return(-1); + } + + if((kmem = open(_PATH_KMEM, 2)) < 0) { + fprintf(stderr, "%s open: %s\n", _PATH_KMEM, + sys_errlist[errno]); + return(-1); + } + + if(stat(ttyline, &statb) < 0) { + fprintf(stderr, "%s stat: %s\n", ttyline, sys_errlist[errno]); + return(-1); + } + + if((statb.st_mode&S_IFMT) != S_IFCHR) { + fprintf(stderr, "%s is not a character device.\n",ttyline); + return(-1); + } + + dev = statb.st_rdev; + (void)lseek(kmem, + (off_t) &(((struct cdevsw *)NLVALUE(CDEVSW))[major(dev)]),0); + (void)read(kmem, (char *) &cdevsw, sizeof cdevsw); + + if((int)(cdevsw.d_open) == NLVALUE(DZOPEN)) { + devtype = DZ11; + unit = minor(dev) / NDZLINE; + line = minor(dev) % NDZLINE; + addr = (int) &(((int *)NLVALUE(DZINFO))[unit]); + (void)lseek(kmem, (off_t) NLVALUE(NDZ11), 0); + } else if((int)(cdevsw.d_open) == NLVALUE(DHOPEN)) { + devtype = DH11; + unit = minor(dev) / NDHLINE; + line = minor(dev) % NDHLINE; + addr = (int) &(((int *)NLVALUE(DHINFO))[unit]); + (void)lseek(kmem, (off_t) NLVALUE(NDH11), 0); + } else if((int)(cdevsw.d_open) == NLVALUE(DMFOPEN)) { + devtype = DMF; + unit = minor(dev) / NDMFLINE; + line = minor(dev) % NDMFLINE; + addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]); + (void)lseek(kmem, (off_t) NLVALUE(NDMF), 0); + } else { + fprintf(stderr, "Device %s (%d/%d) unknown.\n", ttyline, + major(dev), minor(dev)); + return(-1); + } + + (void)read(kmem, (char *) &nlines, sizeof nlines); + if(minor(dev) >= nlines) { + fprintf(stderr, "Sub-device %d does not exist (only %d).\n", + minor(dev), nlines); + return(-1); + } + + (void)lseek(kmem, (off_t)addr, 0); + (void)read(kmem, (char *) &ubinfo, sizeof ubinfo); + (void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0); + (void)read(kmem, (char *) &flags, sizeof flags); + + tflags = 1<ui_flags), 0); + (void)write(kmem, (char *) &flags, sizeof flags); + switch(devtype) { + case DZ11: + if((addr = NLVALUE(DZSCAR)) == 0) { + fprintf(stderr, "No dzsoftCAR.\n"); + return(-1); + } + cflags = flags; + (void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0); + (void)write(kmem, (char *) &cflags, sizeof cflags); + break; + case DH11: + if((addr = NLVALUE(DHSCAR)) == 0) { + fprintf(stderr, "No dhsoftCAR.\n"); + return(-1); + } + sflags = flags; + (void)lseek(kmem, (off_t) &(((short *)addr)[unit]), 0); + (void)write(kmem, (char *) &sflags, sizeof sflags); + break; + case DMF: + if((addr = NLVALUE(DMFSCAR)) == 0) { + fprintf(stderr, "No dmfsoftCAR.\n"); + return(-1); + } + cflags = flags; + (void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0); + (void)write(kmem, (char *) &cflags, sizeof cflags); + break; + default: + fprintf(stderr, "Unknown device type\n"); + return(-1); + } + return(0); +} +#endif /* vax */ + +prefix(s1, s2) + register char *s1, *s2; +{ + register char c; + + while ((c = *s1++) == *s2++) + if (c == '\0') + return (1); + return (c == '\0'); +} +#else /* !DIALINOUT */ +main() +{ + fprintf(stderr,"acucntrl is not supported on this system\n"); +} +#endif /* !DIALINOUT */ diff --git a/usr.bin/uucp/uupoll/Makefile b/usr.bin/uucp/uupoll/Makefile new file mode 100644 index 0000000..fd39c3c --- /dev/null +++ b/usr.bin/uucp/uupoll/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uupoll +CFLAGS+=-I${.CURDIR}/../includes +BINMODE=6555 +DPADD= ${LIBCOMPAT} +LDADD= ${LIBUU} -lcompat +MAN8= uupoll.0 + +.include diff --git a/usr.bin/uucp/uupoll/uupoll.8 b/usr.bin/uucp/uupoll/uupoll.8 new file mode 100644 index 0000000..f6ee49b --- /dev/null +++ b/usr.bin/uucp/uupoll/uupoll.8 @@ -0,0 +1,111 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)uupoll.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UUPOLL 8 +.Os BSD 4.3 +.Sh NAME +.Nm uupoll +.Nd poll a remote +.Tn UUCP +site +.Sh SYNOPSIS +.Nm uupoll +.Op Fl g Ns Ar grade +.Op Fl n +.Ar system +.Sh DESCRIPTION +.Nm Uupoll +is used to force a poll of a remote system. It queues a null job for the +remote system and then invokes +.Xr uucico 8 . +.Pp +The following options are available: +.Bl -tag -width Fl +.It Fl g Ns Ar grade +Only send jobs of grade +.Ar grade +or higher on this call. +.It Fl n +Queue the null job, but do not invoke +.Xr uucico . +.El +.Pp +.Nm Uupoll +is usually run by +.Xr cron 5 +or by a user who wants to hurry a job along. A typical entry in +.Em crontab +could be: +.Bd -literal +0 0,8,16 * * * daemon /usr/bin/uupoll ihnp4 +0 4,12,20 * * * daemon /usr/bin/uupoll ucbvax +.Ed +.Pp +This will poll +.Em ihnp4 +at midnight, 0800, and 1600, and +.Em ucbvax +at 0400, noon, and 2000. +.Pp +If the local machine is already running +.Xr uucico +every +hour and has a limited number of outgoing modems, a more elegant approach +might be: +.Bd -literal +0 0,8,16 * * * daemon /usr/bin/uupoll -n ihnp4 +0 4,12,20 * * * daemon /usr/bin/uupoll -n ucbvax +5 * * * * daemon /usr/lib/uucp/uucico -r1 +.Ed +.Pp +This will queue null jobs for the remote sites at the top of hour; they +will be processed by +.Xr uucico +when it runs five minutes later. +.Sh FILES +.Bl -tag -width /usr/lib/uucp/UUCP -compact +.It Pa /usr/lib/uucp/UUCP +internal files/utilities +.It Pa /var/spool/uucp/ +Spool directory +.El +.Sh SEE ALSO +.Xr uucp 1 , +.Xr uux 1 , +.Xr uucico 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/uucp/uupoll/uupoll.c b/usr.bin/uucp/uupoll/uupoll.c new file mode 100644 index 0000000..5d5e662 --- /dev/null +++ b/usr.bin/uucp/uupoll/uupoll.c @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1986, 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 copyright[] = +"@(#) Copyright (c) 1986, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uupoll.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Poll named system(s). + * + * The poll occurs even if recent attempts have failed, + * but not if L.sys prohibits the call (e.g. wrong time of day). + * + * Original Author: Tom Truscott (rti!trt) + */ + +#include "uucp.h" + +int TransferSucceeded = 1; +struct timeb Now; + +main(argc, argv) +int argc; +char **argv; +{ + char wrkpre[MAXFULLNAME]; + char file[MAXFULLNAME]; + char grade = 'A'; + int nocall = 0; + int c; + char *sysname; + extern char *optarg; + extern int optind; + + if (argc < 2) { + fprintf(stderr, "usage: uupoll [-gX] [-n] system ...\n"); + cleanup(1); + } + + if (chdir(Spool) < 0) { + syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool); + cleanup(1); + } + strcpy(Progname, "uupoll"); + uucpname(Myname); + + while ((c = getopt(argc, argv, "g:n")) != EOF) + switch(c) { + case 'g': + grade = *optarg; + break; + case 'n': + nocall++; + break; + case '?': + default: + fprintf(stderr, "unknown option %s\n", + argv[optind-1]); + } + + while(optind < argc) { + sysname = argv[optind++]; + if (strcmp(sysname, Myname) == SAME) { + fprintf(stderr, "This *is* %s!\n", Myname); + continue; + } + + if (versys(&sysname)) { + fprintf(stderr, "%s: unknown system.\n", sysname); + continue; + } + /* Remove any STST file that might stop the poll */ + sprintf(wrkpre, "%s/LCK..%.*s", LOCKDIR, MAXBASENAME, sysname); + if (access(wrkpre, 0) < 0) + rmstat(sysname); + sprintf(wrkpre, "%c.%.*s", CMDPRE, SYSNSIZE, sysname); + if (!iswrk(file, "chk", Spool, wrkpre)) { + sprintf(file, "%s/%c.%.*s%cPOLL", subdir(Spool, CMDPRE), + CMDPRE, SYSNSIZE, sysname, grade); + close(creat(file, 0666)); + } + /* Attempt the call */ + if (!nocall) + xuucico(sysname); + } + cleanup(0); +} + +cleanup(code) +int code; +{ + exit(code); +} diff --git a/usr.bin/uucp/uuq/Makefile b/usr.bin/uucp/uuq/Makefile new file mode 100644 index 0000000..60dbe0b --- /dev/null +++ b/usr.bin/uucp/uuq/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uuq +CFLAGS+=-I${.CURDIR}/../includes +BINMODE=6555 +DPADD= ${LIBCOMPAT} +LDADD= ${LIBUU} -lcompat + +.include diff --git a/usr.bin/uucp/uuq/uuq.1 b/usr.bin/uucp/uuq/uuq.1 new file mode 100644 index 0000000..783d486 --- /dev/null +++ b/usr.bin/uucp/uuq/uuq.1 @@ -0,0 +1,126 @@ +.\" Copyright (c) 1988, 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. +.\" +.\" @(#)uuq.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UUQ 1 +.Os BSD 4.3 +.Sh NAME +.Nm uuq +.Nd examine or manipulate the uucp queue +.Sh SYNOPSIS +.Nm uuq +.Op Fl l +.Op Fl h +.Op Fl s Ns Ar system +.Op Fl u Ns Ar user +.Op Fl d Ns Ar jobno +.Op Fl r Ns Ar sdir +.Op Fl b Ns Ar baud +.Sh DESCRIPTION +.Nm Uuq +is used to examine (and possibly delete) entries in the uucp queue. +.Pp +When listing jobs, +.Nm uuq +uses a format reminiscent of +.Xr ls . +For the long format, +information for each job listed includes +job number, number of files to transfer, user who +spooled the job, number of bytes to send, type of command requested +(S for sending files, R for receiving files, X for remote uucp), +and file or command desired. +.Pp +Several options are available: +.Bl -tag -width Ar +.It Fl h +Print only the summary lines for each system. Summary lines give system +name, number of jobs for the system, and total number of bytes to send. +.It Fl l +Specifies a long format listing. The default is to list only the +job numbers sorted across the page. +.It Fl s Ns Ar system +Limit output to jobs for systems whose system names begin with +.Ar system . +.It Fl u Ns Ar user +Limit output to jobs for users whose login names begin with +.Ar user . +.It Fl d Ns Ar jobno +Delete job number +.Ar jobno +(as obtained from a previous +.Nm uuq +command) +from the uucp queue. +Only the +.Tn UUCP +Administrator is permitted to delete jobs. +.It Fl r Ns Ar sdir +Look for files in the spooling directory +.Ar sdir +instead of the default +directory. +.It Fl b Ns Ar baud +Use +.Ar baud +to compute the transfer time instead of the default +1200 baud. +.El +.Sh FILES +.Bl -tag -width /usr/spool/uucp/Dhostname./D.x -compact +.It Pa /usr/spool/uucp/ +Default spool directory +.It Pa /usr/spool/uucp/C./C.* +Control files +.It Pa /usr/spool/uucp/D Ns Em hostname ./D.* +Outgoing data files +.It Pa /usr/spool/uucp/X./X.* +Outgoing execution files +.El +.Sh SEE ALSO +.Xr uucp 1 , +.Xr uux 1 , +.Xr uulog 1 , +.Xr uusnap 8 +.Sh BUGS +No information is available on work requested by the remote machine. +.Pp +The user who requests a remote uucp command is unknown. +.Pp +.Dq Li uq \-l +can be horrendously slow. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/usr.bin/uucp/uuq/uuq.c b/usr.bin/uucp/uuq/uuq.c new file mode 100644 index 0000000..7abb25c --- /dev/null +++ b/usr.bin/uucp/uuq/uuq.c @@ -0,0 +1,435 @@ +/*- + * Copyright (c) 1988, 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uuq.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * uuq - looks at uucp queues + * + * Lou Salkind + * New York University + * + */ + +#include "uucp.h" +#include + +#ifdef NDIR +#include "libndir/ndir.h" +#else !NDIR +#include +#endif !NDIR +#include + +#define NOSYS (struct sys *)0 + +#define W_TYPE wrkvec[0] +#define W_FILE1 wrkvec[1] +#define W_FILE2 wrkvec[2] +#define W_USER wrkvec[3] +#define W_OPTNS wrkvec[4] +#define W_DFILE wrkvec[5] +#define W_MODE wrkvec[6] +#define WSUFSIZE 5 /* work file name suffix size */ + +struct sys { + char s_name[8]; + int s_njobs; + off_t s_bytes; + struct job *s_jobp; + struct sys *s_sysp; +}; + +struct job { + int j_files; + int j_flags; + char j_jobno[WSUFSIZE]; + char j_user[22]; + char j_fname[128]; + char j_grade; + off_t j_bytes; + time_t j_date; + struct job *j_jobp; +}; + +struct sys *syshead; +struct sys *getsys(); +int jcompare(); +char *sysname; +char *user; +char *rmjob; +int hflag; +int lflag; + +char *malloc(), *calloc(); +double atof(); +float baudrate = 2400.; +char Username[BUFSIZ]; +char Filename[BUFSIZ]; +int Maxulen = 0; +struct timeb Now; + +main(argc, argv) +int argc; +char **argv; +{ + register int i; + register struct sys *sp; + register struct job *jp; + struct job **sortjob; + int nsys; + extern char *optarg; + extern int optind; + + strcpy(Progname, "uuq"); + uucpname(Myname); + + while ((i = getopt(argc, argv, "r:S:s:u:d:b:hl")) != EOF) + switch (i) { + case 'r': + case 'S': + Spool = optarg; + break; + case 's': + sysname = optarg; + if (strlen(sysname) > SYSNSIZE) + sysname[SYSNSIZE] = '\0'; + break; + case 'u': + user = optarg; + break; + case 'd': + rmjob = optarg; + break; + case 'b': + baudrate = atof(optarg); + break; + case 'h': + hflag++; + break; + case 'l': + lflag++; + break; + default: + fprintf(stderr, + "usage: uuq [-l] [-h] [-ssystem] [-uuser] [-djobno] [-rspool] [-bbaudrate]\n"); + exit(0); + } + + subchdir(Spool); + baudrate *= 0.7; /* reduce speed because of protocol overhead */ + baudrate *= 7.5; /* convert to chars/minute (60/8) */ + gather(); + nsys = 0; + for (sp = syshead; sp; sp = sp->s_sysp) { + if (sp->s_njobs == 0) + continue; + if (!hflag && nsys++ > 0) + putchar('\n'); + printf("%s: %d %s", sp->s_name, + sp->s_njobs, sp->s_njobs > 1 ? "jobs" : "job"); + if (lflag) { + float minutes; + int hours; + /* The 80 * njobs is because of the uucp handshaking */ + minutes = (float)(sp->s_bytes + 80 * sp->s_njobs)/baudrate; + hours = minutes/60; + printf(", %ld bytes, ", sp->s_bytes); + if (minutes > 60){ + printf("%d hour%s, ",hours, + hours > 1 ? "s": ""); + minutes -= 60 * hours; + } + printf("%3.1f minutes (@ effective baudrate of %d)", + minutes,(int)(baudrate/6)); + } + putchar('\n'); + if (hflag) + continue; + /* sort them babies! */ + sortjob = (struct job **)calloc(sp->s_njobs, sizeof (struct job *)); + for (i=0, jp=sp->s_jobp; i < sp->s_njobs; i++, jp=jp->j_jobp) + sortjob[i] = jp; + qsort(sortjob, sp->s_njobs, sizeof (struct job *), jcompare); + for (i = 0; i < sp->s_njobs; i++) { + jp = sortjob[i]; + if (lflag) { + printf("%s %2d %-*s%7ld%5.1f %-12.12s %c %.*s\n", + jp->j_jobno, jp->j_files, Maxulen, jp->j_user, jp->j_bytes, jp->j_bytes/baudrate, + ctime(&jp->j_date) + 4, jp->j_flags, sizeof (jp->j_fname), jp->j_fname + ); + } else { + printf("%s", jp->j_jobno); + putchar((i+1)%10 ? '\t' : '\n'); + } + /* There's no need to keep the force poll if jobs > 1*/ + if (sp->s_njobs > 1 && strcmp("POLL", jp->j_jobno)==0) { + char pbuf[BUFSIZ]; + sprintf(pbuf,"%s/%c.%s%cPOLL", + subdir(Spool, CMDPRE), CMDPRE, + sp->s_name, jp->j_grade); + (void) unlink(pbuf); + } + } + if (!lflag && (sp->s_njobs%10)) + putchar('\n'); + } + exit(0); +} + +jcompare(j1, j2) +struct job **j1, **j2; +{ + int delta; + + delta = (*j1)->j_grade - (*j2)->j_grade; + if (delta) + return delta; + return(strcmp((*j1)->j_jobno,(*j2)->j_jobno)); +} + +/* + * Get all the command file names + */ +gather() +{ + struct direct *d; + DIR *df; + + /* + * Find all the spool files in the spooling directory + */ + if ((df = opendir(subdir(Spool, CMDPRE))) == NULL) { + fprintf(stderr, "can't examine spooling area\n"); + exit(1); + } + for (;;) { + if ((d = readdir(df)) == NULL) + break; + if (d->d_namlen <= 2 || d->d_name[0] != CMDPRE || + d->d_name[1] != '.') + continue; + if (analjob(d->d_name) < 0) { + fprintf(stderr, "out of memory\n"); + break; + } + } + closedir(df); +} + +/* + * analjob does the grunge work of verifying jobs + */ +#include +analjob(filename) +char *filename; +{ + struct job *jp; + struct sys *sp; + char sbuf[MAXNAMLEN+1], str[256], nbuf[256]; + char *jptr, *wrkvec[20]; + char grade; + FILE *fp, *df; + struct stat statb; + int files, gotname, i; + off_t bytes; + + strncpy(sbuf, filename, MAXNAMLEN); + sbuf[MAXNAMLEN] = '\0'; + jptr = sbuf + strlen(sbuf) - WSUFSIZE; + grade = *jptr; + *jptr++ = 0; + /* + * sbuf+2 now points to sysname name (null terminated) + * jptr now points to job number (null terminated) + */ + if (rmjob) { + if (strcmp(rmjob, jptr)) + return(0); + } else { + if ((sp = getsys(sbuf+2)) == NOSYS) + return(0); + if (!lflag) { + /* SHOULD USE A SMALLER STRUCTURE HERE */ + jp = (struct job *)malloc(sizeof(struct job)); + if (jp == (struct job *)0) + return(-1); + strcpy(jp->j_jobno, jptr); + jp->j_jobp = sp->s_jobp; + jp->j_grade = grade; + sp->s_jobp = jp; + sp->s_njobs++; + return(1); + } + } + if ((fp = fopen(subfile(filename), "r")) == NULL) { + perror(subfile(filename)); + return(0); + } + files = 0; + bytes = 0; + gotname = 0; + while (fgets(str, sizeof str, fp)) { + if (getargs(str, wrkvec, 20) <= 0) + continue; + if (rmjob) { + int myuid; + struct passwd *pw; + /* + * Make sure person who is removing data files is + * the person who created it or root. + */ + myuid = getuid(); + pw = getpwnam(W_USER); + if (myuid && (pw == NULL || myuid != pw->pw_uid)) { + fprintf(stderr, "Permission denied.\n"); + exit(1); + } + if (W_TYPE[0] == 'S' && !index(W_OPTNS, 'c')) { + unlink(subfile(W_DFILE)); + fprintf(stderr, "Removing data file %s\n", W_DFILE); + } + continue; + } + if (user && (W_TYPE[0] == 'X' || !prefix(user, W_USER))) { + fclose(fp); + return(0); + } + files++; + if (W_TYPE[0] == 'S') { + if (strcmp(W_DFILE, "D.0") && + stat(subfile(W_DFILE), &statb) >= 0) + bytes += statb.st_size; + else if (stat(subfile(W_FILE1), &statb) >= 0) + bytes += statb.st_size; + } + /* amusing heuristic */ +#define isXfile(s) (s[0]=='D' && s[strlen(s)-WSUFSIZE]=='X') + if (gotname == 0 && isXfile(W_FILE1)) { + if ((df = fopen(subfile(W_FILE1), "r")) == NULL) + continue; + while (fgets(nbuf, sizeof nbuf, df)) { + nbuf[strlen(nbuf) - 1] = '\0'; + if (nbuf[0] == 'C' && nbuf[1] == ' ') { + strcpy(Filename, nbuf+2); + gotname++; + } else if (nbuf[0] == 'R' && nbuf[1] == ' ') { + register char *p, *q, *r; + r = q = p = nbuf+2; + do { + if (*p == '!' || *p == '@'){ + r = q; + q = p+1; + } + } while (*p++); + + strcpy(Username, r); + W_USER = Username; + } + } + fclose(df); + } + } + fclose(fp); + if (rmjob) { + unlink(subfile(filename)); + fprintf(stderr, "Removing command file %s\n", filename); + exit(0); + } + if (files == 0) { + static char *wtype = "X"; + static char *wfile = "forced poll"; + if (strcmp("POLL", &filename[strlen(filename)-4])) { + fprintf(stderr, "%.14s: empty command file\n", filename); + return(0); + } + W_TYPE = wtype; + W_FILE1 = wfile; + } + jp = (struct job *)malloc(sizeof(struct job)); + if (jp == (struct job *)0) + return(-1); + strcpy(jp->j_jobno, jptr); + jp->j_files = files; + jp->j_bytes = bytes; + jp->j_grade = grade; + jp->j_flags = W_TYPE[0]; + strncpy(jp->j_user, W_TYPE[0]=='X' ? "---" : W_USER, 20 ); + jp->j_user[20] = '\0'; + i = strlen(jp->j_user); + if (i > Maxulen) + Maxulen = i; + /* SHOULD ADD ALL INFORMATION IN THE WHILE LOOP */ + if (gotname) + strncpy(jp->j_fname, Filename, sizeof jp->j_fname); + else + strncpy(jp->j_fname, W_FILE1, sizeof jp->j_fname); + stat(subfile(filename), &statb); + jp->j_date = statb.st_mtime; + jp->j_jobp = sp->s_jobp; + sp->s_jobp = jp; + sp->s_njobs++; + sp->s_bytes += jp->j_bytes; + return(1); +} + +struct sys * +getsys(s) +register char *s; +{ + register struct sys *sp; + + for (sp = syshead; sp; sp = sp->s_sysp) + if (strcmp(s, sp->s_name) == 0) + return(sp); + if (sysname && !prefix(sysname, s)) + return(NOSYS); + sp = (struct sys *)malloc(sizeof(struct sys)); + if (sp == NOSYS) + return(NOSYS); + strcpy(sp->s_name, s); + sp->s_njobs = 0; + sp->s_jobp = (struct job *)0; + sp->s_sysp = syshead; + sp->s_bytes = 0; + syshead = sp; + return(sp); +} diff --git a/usr.bin/uucp/uusend/Makefile b/usr.bin/uucp/uusend/Makefile new file mode 100644 index 0000000..6c13fb4 --- /dev/null +++ b/usr.bin/uucp/uusend/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uusend +LINKS= ${BINDIR}/uusend ${BINDIR}/ruusend + +.include diff --git a/usr.bin/uucp/uusend/uusend.1 b/usr.bin/uucp/uusend/uusend.1 new file mode 100644 index 0000000..9379307 --- /dev/null +++ b/usr.bin/uucp/uusend/uusend.1 @@ -0,0 +1,96 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)uusend.1 8.3 (Berkeley) 2/16/94 +.\" +.Dd February 16, 1994 +.Dt UUSEND 1 +.Os BSD 4 +.Sh NAME +.Nm uusend +.Nd send a file to a remote host +.Sh SYNOPSIS +.Nm uusend +.Op Fl m Ar mode +.Ar sourcefile +.Ar sys1!sys2!..!remotefile +.Sh DESCRIPTION +.Nm Uusend +sends a file to a given location on a remote system. +The system need not be directly connected to the local +system, but a chain of +.Xr uucp 1 +links must to connect the two systems. +.Pp +Available option: +.Bl -tag -width Fl +.It Fl m Ar mode +The mode of the file on the remote +end is taken from the octal number given. +Otherwise, the mode of the input file will be used. +.El +.Pp +The sourcefile +can be +.Ql Fl , +meaning to use the standard input. +Both of these options are primarily intended for internal use of +.Nm uusend . +.Pp +The remotefile can include the +.Em ~userid +syntax. +.Sh DIAGNOSTICS +If anything goes wrong any further away than the first system down +the line, you will never hear about it. +.Sh SEE ALSO +.Xr uux 1 , +.Xr uucp 1 , +.Xr uuencode 1 +.Sh BUGS +This command should not exist, since +.Xr uucp +should handle it. +.Pp +All systems along the line must have the +.Nm uusend +command available and allow remote execution of it. +.Pp +Some uucp systems have a bug where binary files cannot be the +input to a +.Xr uux 1 +command. If this bug exists in any system along the line, +the file will show up severely munged. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/uucp/uusend/uusend.c b/usr.bin/uucp/uusend/uusend.c new file mode 100644 index 0000000..207108e --- /dev/null +++ b/usr.bin/uucp/uusend/uusend.c @@ -0,0 +1,403 @@ +/*- + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uusend.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * uusend: primitive operation to allow uucp like copy of binary files + * but handle indirection over systems. + * + * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile + * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile + * + * Author: Mark Horton, May 1980. + * + * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW + * + * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail). + * Checks for illegal access to /usr/lib/uucp. + * February 1983 Christopher Woodbury + * Fixed mode set[ug]id loophole. 4/8/83 CCW + * + * Add '-f' to make uusend syntax more similar to UUCP. "destname" + * can now be a directory. June 1983 CCW + */ + +#include +#include +#include +#include + +/* + * define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp' + * (abbreviation for 'uusend file sys1!sys2!~uucp/file'). + * define DEBUG to keep log of uusend uusage. + * define RUUSEND if neighboring sites permit 'ruusend', + * which they certainly should to avoid security holes + */ +#define RECOVER +/*#define DEBUG "/usr/spool/uucp/uusend.log"/**/ + +FILE *in, *out; +FILE *dout; + +extern FILE *popen(); +extern char *index(), *strcpy(), *strcat(), *ctime(); + +#ifdef RUUSEND +int rsend; +#endif RUUSEND +int mode = -1; /* mode to chmod new file to */ +char *nextsys; /* next system in the chain */ +char dnbuf[200]; /* buffer for result of ~user/file */ +char cmdbuf[256]; /* buffer to build uux command in */ +char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */ + +struct passwd *user; /* entry in /etc/passwd for ~user */ +struct passwd *getpwnam(); +struct stat stbuf; + +char *excl; /* location of first ! in destname */ +char *sl; /* location of first / in destname */ +char *sourcename; /* argv[1] */ +char *destname; /* argv[2] */ +char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */ + +#ifdef RECOVER +char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */ +char *filename; /* file name from end of destname */ +char *getfname(); /* routine to get filename from destname */ +int fflg; +char f[100]; /* name of default output file */ +#else !RECOVER +char *f = ""; /* so we waste a little space */ +#endif !RECOVER + +main(argc, argv) +int argc; +char **argv; +{ + register int c; + long count; + extern char **environ; + +#ifdef DEBUG + long t; + umask(022); + dout = fopen(DEBUG, "a"); + if (dout == NULL) { + printf("Cannot append to %s\n", DEBUG); + exit(1); + } + freopen(DEBUG, "a", stdout); + fprintf(dout, "\nuusend run: "); + for (c=0; c 1 && argv[1][0] == '-' && argv[1][1]) { + switch(argv[1][1]) { + case 'm': + sscanf(argv[2], "%o", &mode); + mode &= 0777; /* fix set[ug]id loophole */ + argc--; argv++; + break; + case 'r': /* -r flag for uux */ + rflg = "-r "; + break; +#ifdef RECOVER + case 'f': + fflg++; + strcpy(f, argv[1]); + break; +#endif RECOVER + default: + fprintf(stderr, "Bad flag: %s\n", argv[1]); + break; + } + argc--; argv++; + } + + if (argc != 3) { + fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n"); + exit(1); + } + + sourcename = argv[1]; + destname = argv[2]; + + if (sourcename[0] == '-') + in = stdin; + else { +#ifdef RUUSEND + if (rsend) { + fprintf(stderr, "illegal input\n"); + exit(2); + } +#endif RUUSEND + in = fopen(sourcename, "r"); + if (in == NULL) { + perror(argv[1]); + exit(2); + } + if (!fflg || f[2] == '\0') { + strcpy(f, "-f"); + strcat(f, getfname(sourcename)); + fflg++; + } + } + + excl = index(destname, '!'); + if (excl) { + /* + * destname is on a remote system. + */ + nextsys = destname; + *excl++ = 0; + destname = excl; + if (mode < 0) { + fstat(fileno(in), &stbuf); + mode = stbuf.st_mode & 0777; + } +#ifdef RUUSEND + sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"", +#else !RUUSEND + sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"", +#endif !RUUSEND + rflg, nextsys, f, mode, destname); +#ifdef DEBUG + fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); +#endif DEBUG + out = popen(cmdbuf, "w"); + } else { + /* + * destname is local. + */ + if (destname[0] == '~') { +#ifdef DEBUG + fprintf(dout, "before ~: '%s'\n", destname); +fflush(dout); +#endif DEBUG + sl = index(destname, '/'); +#ifdef RECOVER + if (sl == NULL && !fflg) { + fprintf(stderr, "Illegal ~user\n"); + exit(3); + } + for (sl = destname; *sl != '\0'; sl++) + ; /* boy, is this a hack! */ +#else !RECOVER + if (sl == NULL) { + fprintf(stderr, "Illegal ~user\n"); + exit(3); + } + *sl++ = 0; +#endif !RECOVER + user = getpwnam(destname+1); + if (user == NULL) { + fprintf(stderr, "No such user as %s\n", + destname); +#ifdef RECOVER + if ((filename =getfname(sl)) == NULL && + !fflg) + exit(4); + strcpy(dnbuf, UUPUB); + if (fflg) + strcat(dnbuf, &f[2]); + else + strcat(dnbuf, filename); + } + else { + strcpy(dnbuf, user->pw_dir); + strcat(dnbuf, "/"); + strcat(dnbuf, sl); + } +#else !RECOVER + exit(4); + } + strcpy(dnbuf, user->pw_dir); + strcat(dnbuf, "/"); + strcat(dnbuf, sl); +#endif !RECOVER + destname = dnbuf; + } +#ifdef RECOVER + else + destname = strcpy(dnbuf, destname); +#endif !RECOVER + if(strncmp(UULIB, destname, strlen(UULIB)) == 0) { + fprintf(stderr, "illegal file: %s", destname); + exit(4); + } +#ifdef RECOVER + if (stat(destname, &stbuf) == 0 && + (stbuf.st_mode & S_IFMT) == S_IFDIR && + fflg) { + strcat(destname, "/"); + strcat(destname, &f[2]); + } +#endif RECOVER + out = fopen(destname, "w"); +#ifdef DEBUG + fprintf(dout, "local, file='%s'\n", destname); +#endif DEBUG + if (out == NULL) { + perror(destname); +#ifdef RECOVER + if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0) + exit(5); /* forget it! */ + filename = getfname(destname); + if (destname == dnbuf) /* cmdbuf is scratch */ + filename = strcpy(cmdbuf, filename); + destname = strcpy(dnbuf, UUPUB); + if (user != NULL) { + strcat(destname, user->pw_name); + if (stat(destname, &stbuf) == -1) { + mkdir(destname, 0777); + } + strcat(destname, "/"); + } + if (fflg) + strcat(destname, &f[2]); + else + strcat(destname, filename); + if ((out = fopen(destname, "w")) == NULL) + exit(5); /* all for naught! */ +#else !RECOVER + exit(5); +#endif !RECOVER + } + if (mode > 0) + chmod(destname, mode); /* don't bother to check it */ + } + + /* + * Now, in any case, copy from in to out. + */ + + count = 0; + while ((c=getc(in)) != EOF) { + putc(c, out); + count++; + } +#ifdef DEBUG + fprintf(dout, "count %ld bytes\n", count); + fclose(dout); +#endif DEBUG + + fclose(in); + fclose(out); /* really should pclose in that case */ + exit(0); +} + +/* + * Return the ptr in sp at which the character c appears; + * NULL if not found. Included so I don't have to fight the + * index/strchr battle. + */ + +#define NULL 0 + +char * +index(sp, c) +register char *sp, c; +{ + do { + if (*sp == c) + return(sp); + } while (*sp++); + return(NULL); +} + +#ifdef RECOVER +char * +getfname(p) +register char *p; +{ + register char *s; + s = p; + while (*p != '\0') + p++; + if (p == s) + return (NULL); + for (;p != s; p--) + if (*p == '/') { + p++; + break; + } + return (p); +} + +#ifndef BSD4_2 +makedir(dirname, mode) +char *dirname; +int mode; +{ + register int pid; + int retcode, status; + switch ((pid = fork())) { + case -1: /* error */ + return (-1); + case 0: /* child */ + umask(0); + execl("/bin/mkdir", "mkdir", dirname, (char *)0); + exit(1); + /* NOTREACHED */ + default: /* parent */ + while ((retcode=wait(&status)) != pid && retcode != -1) + ; + if (retcode == -1) + return -1; + else { + chmod(dirname, mode); + return status; + } + } + /* NOTREACHED */ +} +#endif !BSD4_2 +#endif RECOVER diff --git a/usr.bin/uucp/uusnap/Makefile b/usr.bin/uucp/uusnap/Makefile new file mode 100644 index 0000000..6bf9137 --- /dev/null +++ b/usr.bin/uucp/uusnap/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uusnap +CFLAGS+=-I${.CURDIR}/../includes +BINMODE=6555 +MAN8= uusnap.0 + +.include diff --git a/usr.bin/uucp/uusnap/uusnap.8 b/usr.bin/uucp/uusnap/uusnap.8 new file mode 100644 index 0000000..92f0e330 --- /dev/null +++ b/usr.bin/uucp/uusnap/uusnap.8 @@ -0,0 +1,80 @@ +.\" Copyright (c) 1983, 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. +.\" +.\" @(#)uusnap.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UUSNAP 8 +.Os BSD 4.2 +.Sh NAME +.Nm uusnap +.Nd show snapshot of the +.Tn UUCP +system +.Sh SYNOPSIS +.Nm uusnap +.Sh DESCRIPTION +.Nm Uusnap +displays in tabular format a synopsis of the current +.Tn UUCP +situation. The format of each line is as follows: +.Bd -literal -offset indent -compact + +site N Cmds N Data N Xqts Message + +.Ed +Where "site" is the name of the site with work, "N" is a count of +each of the three possible types of work (command, data, or remote execute), +and "Message" is the current status message for that +site as found in the +.Tn STST +file. +.Pp +Included in "Message" may be the time left before +.Tn UUCP +can re-try the +call, and the count of the number of times that +.Tn UUCP +has tried +(unsuccessfully) to reach the site. +.Sh SEE ALSO +.Xr uucp 1 , +.Xr uux 1 , +.Xr uuq 1 , +.Xr uucico 8 +.Rs +.%T "UUCP Implementation Guide" +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr.bin/uucp/uusnap/uusnap.c b/usr.bin/uucp/uusnap/uusnap.c new file mode 100644 index 0000000..565c52a --- /dev/null +++ b/usr.bin/uucp/uusnap/uusnap.c @@ -0,0 +1,348 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Adams. Originally by RJKing WECo-MG6565 May 83. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uusnap.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "uucp.h" +#include +#ifdef NDIR +#include "ndir.h" +#else +#include +#endif +#include + +#define NSYSTEM 300 /* max # of systems queued */ + +#define CMDSLEN 5 /* Length of trailer */ +#define DATALEN 5 /* Length of trailer */ +#define XEQTLEN 5 /* Length of trailer */ +#define NUMCTRS 3 /* # file types to count */ +#define CMDTYPE 0 /* Index into scnt.cntr */ +#define DATTYPE 1 /* Index into scnt.cntr */ +#define XEQTYPE 2 /* Index into scnt.cntr */ + +struct scnt { /* System count structure */ + char name[MAXBASENAME+1]; /* Name of system */ + short cntr[NUMCTRS]; /* Count */ + char stst[32]; /* STST Message */ + time_t locked; /* If LCK..sys present */ + int st_type; /* STST Type */ + int st_count; /* STST Count */ + time_t st_lastime; /* STST Last time tried */ + time_t st_retry; /* STST Secs to retry */ + }; + +int sndx; /* Number of systems */ +struct scnt sys[NSYSTEM]; /* Systems queued */ +int xqtisrunning = 0; + +main() +{ + register int i, j, nlen = 0; + time_t curtime, t; + + dodir(CMDSDIR, "C.", CMDSLEN, '\0', CMDTYPE); + dodir(DATADIR, "D.", DATALEN, '\0', DATTYPE); + dodir(XEQTDIR, "X.", XEQTLEN, 'X', XEQTYPE); + getstst(SPOOL); + time(&curtime); + for(i=0; i nlen) + nlen = j; + for(i=0; i1?"s":" "); + else + printf(" --- "); + if(sys[i].cntr[DATTYPE]) + printf("%3.d Data ", sys[i].cntr[DATTYPE]); + else + printf(" --- "); + if(sys[i].cntr[XEQTYPE]) + printf("%3.d Xqt%s ", sys[i].cntr[XEQTYPE], + sys[i].cntr[XEQTYPE]>1?"s":" "); + else + printf(" --- "); + if(*sys[i].stst == '\0' || sys[i].locked > sys[i].st_lastime) { + if(sys[i].locked) + printf("LOCKED\n"); + else + printf("\n"); + continue; + } + printf("%s ", sys[i].stst); + /* decide if STST info is worth pursuing */ + if (-t < ONEDAY*2 && (sys[i].st_count == 0 + || sys[i].st_type == SS_WRONGTIME + || (sys[i].st_type == SS_INPROGRESS && sys[i].locked))) { + printf("\n"); + continue; + } + t = (sys[i].st_lastime +sys[i].st_retry) - curtime; + if (-t < ONEDAY*2 && sys[i].st_type != SS_FAIL) + t = 0; + + if (sys[i].st_count > MAXRECALLS) + printf("at MAX RECALLS"); + else if (-t >= ONEDAY*2) + printf("%ld days ago", (long)-t/ONEDAY); + else if (t <= 0) + printf("Retry time reached"); + else if (t < 60) + printf("Retry time %ld sec%s", (long)(t%60), + (t%60)!=1? "s": ""); + else + printf("Retry time %ld min%s", (long)(t/60), + (t/60)!=1? "s": ""); + if(sys[i].st_count > 1) + printf(" Count: %d\n", sys[i].st_count); + else + printf("\n"); + } + if (xqtisrunning) + printf("\nUuxqt is running\n"); + exit(0); +} + +dodir(dnam, prfx, flen, fchr, type) +char *dnam, *prfx; +int flen; +char fchr; +int type; +{ + register struct direct *dentp; + register DIR *dirp; + register int i, fnamlen, plen; + char fnam[MAXNAMLEN+1]; + + plen = strlen(prfx); + if(chdir(dnam) < 0) { + perror(dnam); + exit(1); + } + if ((dirp = opendir(".")) == NULL) { + perror(dnam); + exit(1); + } + while((dentp = readdir(dirp)) != NULL) { + if(*dentp->d_name == '.') + continue; + if(strncmp(dentp->d_name, prfx, plen) != SAME) { + fprintf(stderr, "strange file (%s) in %s\n", + dentp->d_name, dnam); + continue; + } + strcpy(fnam, &dentp->d_name[plen]); + fnamlen = strlen(fnam); + if(flen > 0) { + fnamlen -= flen; + fnam[fnamlen] = '\0'; + fnamlen = MAXBASENAME; /* yes, after = '\0'*/ + } else { + for(; fnamlen>0; --fnamlen) { + if(fnam[fnamlen] == fchr) { + fnam[fnamlen] = '\0'; + break; + } + } + fnamlen = MAXBASENAME; + } + for(i=0; i= NSYSTEM) { + sndx = NSYSTEM-1; + fprintf(stderr,"Too many system names.\n"); + } + } + } + closedir(dirp); +} + +getstst(sdir) +char *sdir; +{ + register int i, csys; + register char *tp; + char fnam[MAXNAMLEN+1], buff[128]; + register struct direct *dentp; + register DIR *dirp; + register FILE *st; + struct stat stbuf; + long atol(); + + if (chdir(sdir) < 0) { + perror(sdir); + exit(1); + } + if ((dirp = opendir(LOCKDIR)) == NULL) { + perror(sdir); + exit(1); + } + while ((dentp = readdir(dirp)) != NULL) { + if (strcmp(&dentp->d_name[5], X_LOCK) == SAME) { + xqtisrunning++; + continue; + } + if(strncmp(dentp->d_name, "LCK..", 5) == SAME) { + if(strncmp(&dentp->d_name[5], "tty", 3) == SAME || + strncmp(&dentp->d_name[5], "cul", 3) == SAME) + continue; + strcpy(fnam, dentp->d_name); + for(csys=0; csysd_name == '.') + continue; + strcpy(fnam, dentp->d_name); + for(csys=0; csys diff --git a/usr.bin/uudecode/uudecode.c b/usr.bin/uudecode/uudecode.c new file mode 100644 index 0000000..af87847 --- /dev/null +++ b/usr.bin/uudecode/uudecode.c @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 1983, 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 +char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * uudecode [file ...] + * + * create the specified file, decoding as you go. + * used with uuencode. + */ +#include +#include + +#include +#include +#include + +char *filename; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int errno; + int rval; + + if (*++argv) { + rval = 0; + do { + if (!freopen(filename = *argv, "r", stdin)) { + (void)fprintf(stderr, "uudecode: %s: %s\n", + *argv, strerror(errno)); + rval = 1; + continue; + } + rval |= decode(); + } while (*++argv); + } else { + filename = "stdin"; + rval = decode(); + } + exit(rval); +} + +decode() +{ + extern int errno; + struct passwd *pw; + register int n; + register char ch, *p; + int mode, n1; + char buf[MAXPATHLEN]; + + /* search for header line */ + do { + if (!fgets(buf, sizeof(buf), stdin)) { + (void)fprintf(stderr, + "uudecode: %s: no \"begin\" line\n", filename); + return(1); + } + } while (strncmp(buf, "begin ", 6)); + (void)sscanf(buf, "begin %o %s", &mode, buf); + + /* handle ~user/file format */ + if (buf[0] == '~') { + if (!(p = index(buf, '/'))) { + (void)fprintf(stderr, "uudecode: %s: illegal ~user.\n", + filename); + return(1); + } + *p++ = NULL; + if (!(pw = getpwnam(buf + 1))) { + (void)fprintf(stderr, "uudecode: %s: no user %s.\n", + filename, buf); + return(1); + } + n = strlen(pw->pw_dir); + n1 = strlen(p); + if (n + n1 + 2 > MAXPATHLEN) { + (void)fprintf(stderr, "uudecode: %s: path too long.\n", + filename); + return(1); + } + bcopy(p, buf + n + 1, n1 + 1); + bcopy(pw->pw_dir, buf, n); + buf[n] = '/'; + } + + /* create output file, set mode */ + if (!freopen(buf, "w", stdout) || + fchmod(fileno(stdout), mode&0666)) { + (void)fprintf(stderr, "uudecode: %s: %s: %s\n", buf, + filename, strerror(errno)); + return(1); + } + + /* for each input line */ + for (;;) { + if (!fgets(p = buf, sizeof(buf), stdin)) { + (void)fprintf(stderr, "uudecode: %s: short file.\n", + filename); + return(1); + } +#define DEC(c) (((c) - ' ') & 077) /* single character decode */ + /* + * `n' is used to avoid writing out all the characters + * at the end of the file. + */ + if ((n = DEC(*p)) <= 0) + break; + for (++p; n > 0; p += 4, n -= 3) + if (n >= 3) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + putchar(ch); + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + putchar(ch); + ch = DEC(p[2]) << 6 | DEC(p[3]); + putchar(ch); + } + else { + if (n >= 1) { + ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4; + putchar(ch); + } + if (n >= 2) { + ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2; + putchar(ch); + } + if (n >= 3) { + ch = DEC(p[2]) << 6 | DEC(p[3]); + putchar(ch); + } + } + } + if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) { + (void)fprintf(stderr, "uudecode: %s: no \"end\" line.\n", + filename); + return(1); + } + return(0); +} + +usage() +{ + (void)fprintf(stderr, "usage: uudecode [file ...]\n"); + exit(1); +} diff --git a/usr.bin/uuencode/Makefile b/usr.bin/uuencode/Makefile new file mode 100644 index 0000000..051a6fe --- /dev/null +++ b/usr.bin/uuencode/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= uuencode +MAN1= uuencode.0 +MAN5= uuencode.format.0 +MLINKS= uuencode.1 uudecode.1 + +.include diff --git a/usr.bin/uuencode/uuencode.1 b/usr.bin/uuencode/uuencode.1 new file mode 100644 index 0000000..df1ebf2 --- /dev/null +++ b/usr.bin/uuencode/uuencode.1 @@ -0,0 +1,105 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)uuencode.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt UUENCODE 1 +.Os BSD 4 +.Sh NAME +.Nm uuencode , +.Nm uudecode +.Nd encode/decode a binary file +.Sh SYNOPSIS +.Nm uuencode +.Op Ar file +.Ar name +.Nm uudecode +.Op Ar file ... +.Sh DESCRIPTION +.Nm Uuencode +and +.Nm uudecode +are used to transmit binary files over transmission mediums +that do not support other than simple +.Tn ASCII +data. +.Pp +.Nm Uuencode +reads +.Ar file +(or by default the standard input) and writes an encoded version +to the standard output. +The encoding uses only printing +.Tn ASCII +characters and includes the +mode of the file and the operand +.Ar name +for use by +.Nm uudecode . +.Pp +.Nm Uudecode +transforms +.Em uuencoded +files (or by default, the standard input) into the original form. +The resulting file is named +.Ar name +and will have the mode of the original file except that setuid +and execute bits are not retained. +.Nm Uudecode +ignores any leading and trailing lines. +.Sh EXAMPLES +The following example packages up a source tree, compresses it, +uuencodes it and mails it to a user on another system. +When +.Nm uudecode +is run on the target system, the file ``src_tree.tar.Z'' will be +created which may then be uncompressed and extracted into the original +tree. +.Pp +.Bd -literal -offset indent -compact +tar cf \- src_tree \&| compress \&| +uuencode src_tree.tar.Z \&| mail sys1!sys2!user +.Ed +.Sh SEE ALSO +.Xr compress 1 , +.Xr mail 1 , +.Xr uucp 1 , +.Xr uuencode 5 , +.Xr format 5 +.Sh BUGS +The encoded form of the file is expanded by 35% (3 bytes become 4 plus +control information). +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/uuencode/uuencode.c b/usr.bin/uuencode/uuencode.c new file mode 100644 index 0000000..774cee9 --- /dev/null +++ b/usr.bin/uuencode/uuencode.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 1983, 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 +char copyright[] = +"@(#) Copyright (c) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)uuencode.c 8.2 (Berkeley) 4/2/94"; +#endif /* not lint */ + +/* + * uuencode [input] output + * + * Encode a file so it can be mailed to a remote system. + */ +#include +#include + +#include + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern int errno; + struct stat sb; + int mode; + char *strerror(); + + while (getopt(argc, argv, "") != EOF) + usage(); + argv += optind; + argc -= optind; + + switch(argc) { + case 2: /* optional first argument is input file */ + if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb)) { + (void)fprintf(stderr, "uuencode: %s: %s.\n", + *argv, strerror(errno)); + exit(1); + } +#define RWX (S_IRWXU|S_IRWXG|S_IRWXO) + mode = sb.st_mode & RWX; + ++argv; + break; + case 1: +#define RW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) + mode = RW & ~umask(RW); + break; + case 0: + default: + usage(); + } + + (void)printf("begin %o %s\n", mode, *argv); + encode(); + (void)printf("end\n"); + if (ferror(stdout)) { + (void)fprintf(stderr, "uuencode: write error.\n"); + exit(1); + } + exit(0); +} + +/* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) ((c) ? ((c) & 077) + ' ': '`') + +/* + * copy from in to out, encoding as you go along. + */ +encode() +{ + register int ch, n; + register char *p; + char buf[80]; + + while (n = fread(buf, 1, 45, stdin)) { + ch = ENC(n); + if (putchar(ch) == EOF) + break; + for (p = buf; n > 0; n -= 3, p += 3) { + ch = *p >> 2; + ch = ENC(ch); + if (putchar(ch) == EOF) + break; + ch = (*p << 4) & 060 | (p[1] >> 4) & 017; + ch = ENC(ch); + if (putchar(ch) == EOF) + break; + ch = (p[1] << 2) & 074 | (p[2] >> 6) & 03; + ch = ENC(ch); + if (putchar(ch) == EOF) + break; + ch = p[2] & 077; + ch = ENC(ch); + if (putchar(ch) == EOF) + break; + } + if (putchar('\n') == EOF) + break; + } + if (ferror(stdin)) { + (void)fprintf(stderr, "uuencode: read error.\n"); + exit(1); + } + ch = ENC('\0'); + (void)putchar(ch); + (void)putchar('\n'); +} + +usage() +{ + (void)fprintf(stderr,"usage: uuencode [infile] remotefile\n"); + exit(1); +} diff --git a/usr.bin/uuencode/uuencode.format.5 b/usr.bin/uuencode/uuencode.format.5 new file mode 100644 index 0000000..81591b8 --- /dev/null +++ b/usr.bin/uuencode/uuencode.format.5 @@ -0,0 +1,102 @@ +.\" Copyright (c) 1989, 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. +.\" +.\" @(#)uuencode.format.5 8.2 (Berkeley) 1/12/94 +.\" +.Dd January 12, 1994 +.Dt UUENCODE 5 +.Os BSD 4 +.Sh NAME +.Nm uuencode +.Nd format of an encoded uuencode file +.Sh DESCRIPTION +Files output by +.Xr uuencode 1 +consist of a header line, +followed by a number of body lines, +and a trailer line. +The +.Xr uudecode 1 +command +will ignore any lines preceding the header or +following the trailer. +Lines preceding a header must not, of course, +look like a header. +.Pp +The header line is distinguished by having the first +6 characters +.Dq begin\ \& +(note the trailing space). +The word +.Em begin +is followed by a mode (in octal), +and a string which names the remote file. +A space separates the three items in the header line. +.Pp +The body consists of a number of lines, each at most 62 characters +long (including the trailing newline). +These consist of a character count, +followed by encoded characters, +followed by a newline. +The character count is a single printing character, +and represents an integer, the number of bytes +the rest of the line represents. +Such integers are always in the range from 0 to 63 and can +be determined by subtracting the character space (octal 40) +from the character. +.Pp +Groups of 3 bytes are stored in 4 characters, 6 bits per character. +All are offset by a space to make the characters printing. +The last line may be shorter than the normal 45 bytes. +If the size is not a multiple of 3, this fact can be determined +by the value of the count on the last line. +Extra garbage will be included to make the character count a multiple +of 4. +The body is terminated by a line with a count of zero. +This line consists of one +.Tn ASCII +space. +.Pp +The trailer line consists of +.Dq end +on a line by itself. +.Sh SEE ALSO +.Xr uuencode 1 , +.Xr uudecode 1 , +.Xr uusend 1 , +.Xr uucp 1 , +.Xr mail 1 +.Sh HISTORY +The +.Nm uuencode +file format appeared in +.Bx 4.0 . +.\" It was named uuencode.5 prior to 4.3 diff --git a/usr.bin/vacation/Makefile b/usr.bin/vacation/Makefile new file mode 100644 index 0000000..130d439 --- /dev/null +++ b/usr.bin/vacation/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= vacation +DPADD= ${LIBDBM} + +.include diff --git a/usr.bin/vacation/vacation.1 b/usr.bin/vacation/vacation.1 new file mode 100644 index 0000000..0c74c39 --- /dev/null +++ b/usr.bin/vacation/vacation.1 @@ -0,0 +1,171 @@ +.\" Copyright (c) 1985, 1987, 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. +.\" +.\" @(#)vacation.1 8.1 (Berkeley) 6/16/93 +.\" +.Dd June 16, 1993 +.Dt VACATION 1 +.Os BSD 4.3 +.Sh NAME +.Nm vacation +.Nd return ``I am not here'' indication +.Sh SYNOPSIS +.Nm vacation +.Fl i +.Op Fl r Ar interval +.Nm vacation +.Op Fl a Ar alias +.Ar login +.Sh DESCRIPTION +.Nm Vacation +returns a message to the sender of a message telling them that you +are currently not reading your mail. The intended use is in a +.Pa .forward +file. For example, your +.Pa .forward +file might have: +.Bd -literal -offset indent +\eeric, "|/usr/bin/vacation -a allman eric" +.Ed +which would send messages to you (assuming your login name was eric) and +reply to any messages for +.Dq eric +or +.Dq allman . +.Pp +Available options: +.Bl -tag -width Ds +.It Fl a Ar alias +Handle messages for +.Ar alias +in the same manner as those received for the user's +login name. +.It Fl i +Initialize the vacation database files. It should be used +before you modify your +.Pa .forward +file. +.It Fl r +Set the reply interval to +.Ar interval +days. The default is one week. An interval of +.Dq 0 +means that +a reply is sent to each message, and an interval of +.Dq Li infinite +(actually, any non-numeric character) will never send more than +one reply. It should be noted that intervals of +.Dq Li \&0 +are quite +dangerous, as it allows mailers to get into +.Dq I am on vacation +loops. +.El +.Pp +No message will be sent unless +.Ar login +(or an +.Ar alias +supplied using the +.Fl a +option) is part of either the +.Dq To: +or +.Dq Cc: +headers of the mail. +No messages from +.Dq ???-REQUEST , +.Dq Postmaster , +.Dq Tn UUCP , +.Dq MAILER , +or +.Dq MAILER-DAEMON +will be replied to (where these strings are +case insensitive) nor is a notification sent if a +.Dq Precedence: bulk +or +.Dq Precedence: junk +line is included in the mail headers. +The people who have sent you messages are maintained as an +.Xr ndbm 3 +database in the file +.Pa .vacation.db +in your home directory. +.Pp +.Nm Vacation +expects a file +.Pa .vacation.msg , +in your home directory, containing a message to be sent back to each +sender. It should be an entire message (including headers). For +example, it might contain: +.Pp +.Bd -unfilled -offset indent -compact +From: eric@CS.Berkeley.EDU (Eric Allman) +Subject: I am on vacation +Delivered-By-The-Graces-Of: The Vacation program +Precedence: bulk + +I am on vacation until July 22. If you have something urgent, +please contact Keith Bostic . +--eric +.Ed +.Pp +.Nm Vacation +reads the first line from the standard input for a +.Ux +.Dq From +line to determine the sender. +.Xr Sendmail 8 +includes this +.Dq From +line automatically. +.Pp +Fatal errors, such as calling +.Nm vacation +with incorrect arguments, or with non-existent +.Ar login Ns Ar s , +are logged in the system log file, using +.Xr syslog 8 . +.Sh FILES +.Bl -tag -width "vacation.dirxxx" -compact +.It Pa ~/.vacation.db +database file +.It Pa ~/.vacation.msg +message to send +.El +.Sh SEE ALSO +.Xr sendmail 8 , +.Xr syslog 8 +.Sh HISTORY +The +.Nm vacation +command appeared in +.Bx 4.3 . diff --git a/usr.bin/vacation/vacation.c b/usr.bin/vacation/vacation.c new file mode 100644 index 0000000..025eb98 --- /dev/null +++ b/usr.bin/vacation/vacation.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 1983, 1987, 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 copyright[] = +"@(#) Copyright (c) 1983, 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94"; +#endif /* not lint */ + +/* +** Vacation +** Copyright (c) 1983 Eric P. Allman +** Berkeley, California +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * VACATION -- return a message to the sender when on vacation. + * + * This program is invoked as a message receiver. It returns a + * message specified by the user to whomever sent the mail, taking + * care not to return a message too often to prevent "I am on + * vacation" loops. + */ + +#define MAXLINE 1024 /* max line from mail header */ +#define VDB ".vacation.db" /* dbm's database */ +#define VMSG ".vacation.msg" /* vacation message */ + +typedef struct alias { + struct alias *next; + char *name; +} ALIAS; +ALIAS *names; + +DB *db; + +char from[MAXLINE]; + +main(argc, argv) + int argc; + char **argv; +{ + extern int optind, opterr; + extern char *optarg; + struct passwd *pw; + ALIAS *cur; + time_t interval; + int ch, iflag; + + opterr = iflag = 0; + interval = -1; + while ((ch = getopt(argc, argv, "a:Iir:")) != EOF) + switch((char)ch) { + case 'a': /* alias */ + if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)))) + break; + cur->name = optarg; + cur->next = names; + names = cur; + break; + case 'I': /* backward compatible */ + case 'i': /* init the database */ + iflag = 1; + break; + case 'r': + if (isdigit(*optarg)) { + interval = atol(optarg) * SECSPERDAY; + if (interval < 0) + usage(); + } + else + interval = LONG_MAX; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) { + if (!iflag) + usage(); + if (!(pw = getpwuid(getuid()))) { + syslog(LOG_ERR, + "vacation: no such user uid %u.\n", getuid()); + exit(1); + } + } + else if (!(pw = getpwnam(*argv))) { + syslog(LOG_ERR, "vacation: no such user %s.\n", *argv); + exit(1); + } + if (chdir(pw->pw_dir)) { + syslog(LOG_NOTICE, + "vacation: no such directory %s.\n", pw->pw_dir); + exit(1); + } + + db = dbopen(VDB, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), + S_IRUSR|S_IWUSR, DB_HASH, NULL); + if (!db) { + syslog(LOG_NOTICE, "vacation: %s: %s\n", VDB, strerror(errno)); + exit(1); + } + + if (interval != -1) + setinterval(interval); + + if (iflag) { + (void)(db->close)(db); + exit(0); + } + + if (!(cur = malloc((u_int)sizeof(ALIAS)))) + exit(1); + cur->name = pw->pw_name; + cur->next = names; + names = cur; + + readheaders(); + if (!recent()) { + setreply(); + (void)(db->close)(db); + sendmessage(pw->pw_name); + } + else + (void)(db->close)(db); + exit(0); + /* NOTREACHED */ +} + +/* + * readheaders -- + * read mail headers + */ +readheaders() +{ + register ALIAS *cur; + register char *p; + int tome, cont; + char buf[MAXLINE]; + + cont = tome = 0; + while (fgets(buf, sizeof(buf), stdin) && *buf != '\n') + switch(*buf) { + case 'F': /* "From " */ + cont = 0; + if (!strncmp(buf, "From ", 5)) { + for (p = buf + 5; *p && *p != ' '; ++p); + *p = '\0'; + (void)strcpy(from, buf + 5); + if (p = index(from, '\n')) + *p = '\0'; + if (junkmail()) + exit(0); + } + break; + case 'P': /* "Precedence:" */ + cont = 0; + if (strncasecmp(buf, "Precedence", 10) || + buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t') + break; + if (!(p = index(buf, ':'))) + break; + while (*++p && isspace(*p)); + if (!*p) + break; + if (!strncasecmp(p, "junk", 4) || + !strncasecmp(p, "bulk", 4) || + !strncasecmp(p, "list", 4)) + exit(0); + break; + case 'C': /* "Cc:" */ + if (strncmp(buf, "Cc:", 3)) + break; + cont = 1; + goto findme; + case 'T': /* "To:" */ + if (strncmp(buf, "To:", 3)) + break; + cont = 1; + goto findme; + default: + if (!isspace(*buf) || !cont || tome) { + cont = 0; + break; + } +findme: for (cur = names; !tome && cur; cur = cur->next) + tome += nsearch(cur->name, buf); + } + if (!tome) + exit(0); + if (!*from) { + syslog(LOG_NOTICE, "vacation: no initial \"From\" line.\n"); + exit(1); + } +} + +/* + * nsearch -- + * do a nice, slow, search of a string for a substring. + */ +nsearch(name, str) + register char *name, *str; +{ + register int len; + + for (len = strlen(name); *str; ++str) + if (*str == *name && !strncasecmp(name, str, len)) + return(1); + return(0); +} + +/* + * junkmail -- + * read the header and return if automagic/junk/bulk/list mail + */ +junkmail() +{ + static struct ignore { + char *name; + int len; + } ignore[] = { + "-request", 8, "postmaster", 10, "uucp", 4, + "mailer-daemon", 13, "mailer", 6, "-relay", 6, + NULL, NULL, + }; + register struct ignore *cur; + register int len; + register char *p; + + /* + * This is mildly amusing, and I'm not positive it's right; trying + * to find the "real" name of the sender, assuming that addresses + * will be some variant of: + * + * From site!site!SENDER%site.domain%site.domain@site.domain + */ + if (!(p = index(from, '%'))) + if (!(p = index(from, '@'))) { + if (p = rindex(from, '!')) + ++p; + else + p = from; + for (; *p; ++p); + } + len = p - from; + for (cur = ignore; cur->name; ++cur) + if (len >= cur->len && + !strncasecmp(cur->name, p - cur->len, cur->len)) + return(1); + return(0); +} + +#define VIT "__VACATION__INTERVAL__TIMER__" + +/* + * recent -- + * find out if user has gotten a vacation message recently. + * use bcopy for machines with alignment restrictions + */ +recent() +{ + DBT key, data; + time_t then, next; + + /* get interval time */ + key.data = VIT; + key.size = sizeof(VIT); + if ((db->get)(db, &key, &data, 0)) + next = SECSPERDAY * DAYSPERWEEK; + else + bcopy(data.data, &next, sizeof(next)); + + /* get record for this address */ + key.data = from; + key.size = strlen(from); + if (!(db->get)(db, &key, &data, 0)) { + bcopy(data.data, &then, sizeof(then)); + if (next == LONG_MAX || then + next > time(NULL)) + return(1); + } + return(0); +} + +/* + * setinterval -- + * store the reply interval + */ +setinterval(interval) + time_t interval; +{ + DBT key, data; + + key.data = VIT; + key.size = sizeof(VIT); + data.data = &interval; + data.size = sizeof(interval); + (void)(db->put)(db, &key, &data, 0); +} + +/* + * setreply -- + * store that this user knows about the vacation. + */ +setreply() +{ + DBT key, data; + time_t now; + + key.data = from; + key.size = strlen(from); + (void)time(&now); + data.data = &now; + data.size = sizeof(now); + (void)(db->put)(db, &key, &data, 0); +} + +/* + * sendmessage -- + * exec sendmail to send the vacation file to sender + */ +sendmessage(myname) + char *myname; +{ + FILE *mfp, *sfp; + int i; + int pvect[2]; + char buf[MAXLINE]; + + mfp = fopen(VMSG, "r"); + if (mfp == NULL) { + syslog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG); + exit(1); + } + if (pipe(pvect) < 0) { + syslog(LOG_ERR, "vacation: pipe: %s", strerror(errno)); + exit(1); + } + i = vfork(); + if (i < 0) { + syslog(LOG_ERR, "vacation: fork: %s", strerror(errno)); + exit(1); + } + if (i == 0) { + dup2(pvect[0], 0); + close(pvect[0]); + close(pvect[1]); + fclose(mfp); + execl(_PATH_SENDMAIL, "sendmail", "-f", myname, from, NULL); + syslog(LOG_ERR, "vacation: can't exec %s: %s", + _PATH_SENDMAIL, strerror(errno)); + exit(1); + } + close(pvect[0]); + sfp = fdopen(pvect[1], "w"); + fprintf(sfp, "To: %s\n", from); + while (fgets(buf, sizeof buf, mfp)) + fputs(buf, sfp); + fclose(mfp); + fclose(sfp); +} + +usage() +{ + syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] login\n", + getuid()); + exit(1); +} diff --git a/usr.bin/vgrind/Makefile b/usr.bin/vgrind/Makefile new file mode 100644 index 0000000..0bd4f00 --- /dev/null +++ b/usr.bin/vgrind/Makefile @@ -0,0 +1,21 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= vfontedpr +SRCS= regexp.c vfontedpr.c +MAN1= vgrind.0 +MAN5= vgrindefs.0 +BINDIR= /usr/libexec +CLEANFILES+=vgrindefs.src.db + +beforeinstall: + cap_mkdb -f vgrindefs.src ${.CURDIR}/vgrindefs.src + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/vgrind.sh ${DESTDIR}/usr/bin/vgrind + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/vgrindefs.src \ + ${DESTDIR}/usr/share/misc/vgrindefs + install -c -o ${BINOWN} -g ${BINGRP} -m 444 \ + vgrindefs.src.db ${DESTDIR}/usr/share/misc/vgrindefs.db + install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/tmac.vgrind \ + ${DESTDIR}/usr/share/tmac + +.include diff --git a/usr.bin/vgrind/RETEST/Makefile b/usr.bin/vgrind/RETEST/Makefile new file mode 100644 index 0000000..1e50c81 --- /dev/null +++ b/usr.bin/vgrind/RETEST/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= retest +SRCS= regexp.c retest.c +.PATH: ${.CURDIR}/.. +NOMAN= noman + +install: + +.include diff --git a/usr.bin/vgrind/RETEST/retest.c b/usr.bin/vgrind/RETEST/retest.c new file mode 100644 index 0000000..ce953cb --- /dev/null +++ b/usr.bin/vgrind/RETEST/retest.c @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)retest.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +int l_onecase = 0; +char * _start; +char * _escaped; +char * convexp(); +char * expmatch(); +main() +{ + char reg[132]; + char *ireg; + char str[132]; + char *match; + char matstr[132]; + char c; + + while (1) { + printf ("\nexpr: "); + scanf ("%s", reg); + ireg = convexp(reg); + match = ireg; + while(*match) { + switch (*match) { + + case '\\': + case '(': + case ')': + case '|': + printf ("%c", *match); + break; + + default: + if (isalnum(*match)) + printf("%c", *match); + else + printf ("<%03o>", *match); + break; + } + match++; + } + printf("\n"); + getchar(); + while(1) { + printf ("string: "); + match = str; + while ((c = getchar()) != '\n') + *match++ = c; + *match = 0; + if (str[0] == '#') + break; + matstr[0] = 0; + _start = str; + _escaped = 0; + match = expmatch (str, ireg, matstr); + if (match == 0) + printf ("FAILED\n"); + else + printf ("match\nmatstr = %s\n", matstr); + } + + } +} diff --git a/usr.bin/vgrind/extern.h b/usr.bin/vgrind/extern.h new file mode 100644 index 0000000..0526d56 --- /dev/null +++ b/usr.bin/vgrind/extern.h @@ -0,0 +1,65 @@ +/* + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +typedef int boolean; + +extern boolean _escaped; /* if last character was an escape */ +extern char *_start; /* start of the current string */ +extern char *l_acmbeg; /* string introducing a comment */ +extern char *l_acmend; /* string ending a comment */ +extern char *l_blkbeg; /* string begining of a block */ +extern char *l_blkend; /* string ending a block */ +extern char *l_chrbeg; /* delimiter for character constant */ +extern char *l_chrend; /* delimiter for character constant */ +extern char *l_combeg; /* string introducing a comment */ +extern char *l_comend; /* string ending a comment */ +extern char l_escape; /* character used to escape characters */ +extern char *l_keywds[]; /* keyword table address */ +extern boolean l_onecase; /* upper and lower case are equivalent */ +extern char *l_prcbeg; /* regular expr for procedure begin */ +extern char *l_strbeg; /* delimiter for string constant */ +extern char *l_strend; /* delimiter for string constant */ +extern boolean l_toplex; /* procedures only defined at top lex level */ +extern char *language; /* the language indicator */ + +#include + +__BEGIN_DECLS +extern int STRNCMP __P((char *, char *, int)); +extern char *convexp __P((char *)); +extern char *expmatch __P((char *, char *, char *)); +__END_DECLS + diff --git a/usr.bin/vgrind/pathnames.h b/usr.bin/vgrind/pathnames.h new file mode 100644 index 0000000..157f91f --- /dev/null +++ b/usr.bin/vgrind/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_VGRINDEFS "/usr/share/misc/vgrindefs" diff --git a/usr.bin/vgrind/regexp.c b/usr.bin/vgrind/regexp.c new file mode 100644 index 0000000..978af65 --- /dev/null +++ b/usr.bin/vgrind/regexp.c @@ -0,0 +1,593 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)regexp.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include "extern.h" + +#define FALSE 0 +#define TRUE !(FALSE) +#define NIL 0 + +static void expconv __P((void)); + +boolean _escaped; /* true if we are currently _escaped */ +char *_start; /* start of string */ +boolean l_onecase; /* true if upper and lower equivalent */ + +#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) + +/* STRNCMP - like strncmp except that we convert the + * first string to lower case before comparing + * if l_onecase is set. + */ + +int +STRNCMP(s1, s2, len) + register char *s1,*s2; + register int len; +{ + if (l_onecase) { + do + if (*s2 - makelower(*s1)) + return (*s2 - makelower(*s1)); + else { + s2++; + s1++; + } + while (--len); + } else { + do + if (*s2 - *s1) + return (*s2 - *s1); + else { + s2++; + s1++; + } + while (--len); + } + return(0); +} + +/* The following routine converts an irregular expression to + * internal format. + * + * Either meta symbols (\a \d or \p) or character strings or + * operations ( alternation or perenthesizing ) can be + * specified. Each starts with a descriptor byte. The descriptor + * byte has STR set for strings, META set for meta symbols + * and OPER set for operations. + * The descriptor byte can also have the OPT bit set if the object + * defined is optional. Also ALT can be set to indicate an alternation. + * + * For metasymbols the byte following the descriptor byte identities + * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For + * strings the byte after the descriptor is a character count for + * the string: + * + * meta symbols := descriptor + * symbol + * + * strings := descriptor + * character count + * the string + * + * operatins := descriptor + * symbol + * character count + */ + +/* + * handy macros for accessing parts of match blocks + */ +#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ +#define MNEXT(A) (A+2) /* character following a metasymbol block */ + +#define OSYM(A) (*(A+1)) /* symbol in an operation block */ +#define OCNT(A) (*(A+2)) /* character count */ +#define ONEXT(A) (A+3) /* next character after the operation */ +#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ + +#define SCNT(A) (*(A+1)) /* byte count of a string */ +#define SSTR(A) (A+2) /* address of the string */ +#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ + +/* + * bit flags in the descriptor + */ +#define OPT 1 +#define STR 2 +#define META 4 +#define ALT 8 +#define OPER 16 + +static char *ccre; /* pointer to current position in converted exp*/ +static char *ure; /* pointer current position in unconverted exp */ + +char * +convexp(re) + char *re; /* unconverted irregular expression */ +{ + register char *cre; /* pointer to converted regular expression */ + + /* allocate room for the converted expression */ + if (re == NIL) + return (NIL); + if (*re == '\0') + return (NIL); + cre = malloc (4 * strlen(re) + 3); + ccre = cre; + ure = re; + + /* start the conversion with a \a */ + *cre = META | OPT; + MSYM(cre) = 'a'; + ccre = MNEXT(cre); + + /* start the conversion (its recursive) */ + expconv (); + *ccre = 0; + return (cre); +} + +static void +expconv() +{ + register char *cs; /* pointer to current symbol in converted exp */ + register char c; /* character being processed */ + register char *acs; /* pinter to last alternate */ + register int temp; + + /* let the conversion begin */ + acs = NIL; + cs = NIL; + while (*ure != NIL) { + switch (c = *ure++) { + + case '\\': + switch (c = *ure++) { + + /* escaped characters are just characters */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre += 2; + } else + SCNT(cs)++; + *ccre++ = c; + break; + + /* normal(?) metacharacters */ + case 'a': + case 'd': + case 'e': + case 'p': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + } + break; + + /* just put the symbol in */ + case '^': + case '$': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + + /* mark the last match sequence as optional */ + case '?': + if (cs) + *cs = *cs | OPT; + break; + + /* recurse and define a subexpression */ + case '(': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = OPER; + OSYM(cs) = '('; + ccre = ONEXT(cs); + expconv (); + OCNT(cs) = ccre - cs; /* offset to next symbol */ + break; + + /* reurn from a recursion */ + case ')': + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + return; + + /* mark the last match sequence as having an alternate */ + /* the third byte will contain an offset to jump over the */ + /* alternate match in case the first did not fail */ + case '|': + if (acs != NIL && acs != cs) + OCNT(ccre) = ccre - acs; /* make a back pointer */ + else + OCNT(ccre) = 0; + *cs |= ALT; + cs = ccre; + *cs = OPER; + OSYM(cs) = '|'; + ccre = ONEXT(cs); + acs = cs; /* remember that the pointer is to be filles */ + break; + + /* if its not a metasymbol just build a scharacter string */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre = SSTR(cs); + } else + SCNT(cs)++; + *ccre++ = c; + break; + } + } + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + return; +} +/* end of convertre */ + + +/* + * The following routine recognises an irregular expresion + * with the following special characters: + * + * \? - means last match was optional + * \a - matches any number of characters + * \d - matches any number of spaces and tabs + * \p - matches any number of alphanumeric + * characters. The + * characters matched will be copied into + * the area pointed to by 'name'. + * \| - alternation + * \( \) - grouping used mostly for alternation and + * optionality + * + * The irregular expression must be translated to internal form + * prior to calling this routine + * + * The value returned is the pointer to the first non \a + * character matched. + */ + +char * +expmatch (s, re, mstring) + register char *s; /* string to check for a match in */ + register char *re; /* a converted irregular expression */ + register char *mstring; /* where to put whatever matches a \p */ +{ + register char *cs; /* the current symbol */ + register char *ptr,*s1; /* temporary pointer */ + boolean matched; /* a temporary boolean */ + + /* initial conditions */ + if (re == NIL) + return (NIL); + cs = re; + matched = FALSE; + + /* loop till expression string is exhausted (or at least pretty tired) */ + while (*cs) { + switch (*cs & (OPER | STR | META)) { + + /* try to match a string */ + case STR: + matched = !STRNCMP (s, SSTR(cs), SCNT(cs)); + if (matched) { + + /* hoorah it matches */ + s += SCNT(cs); + cs = SNEXT(cs); + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + cs = SNEXT(cs); + } else if (*cs & OPT) { + + /* the match is optional */ + cs = SNEXT(cs); + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + break; + + /* an operator, do something fancy */ + case OPER: + switch (OSYM(cs)) { + + /* this is an alternation */ + case '|': + if (matched) + + /* last thing in the alternation was a match, skip ahead */ + cs = OPTR(cs); + else + + /* no match, keep trying */ + cs = ONEXT(cs); + break; + + /* this is a grouping, recurse */ + case '(': + ptr = expmatch (s, ONEXT(cs), mstring); + if (ptr != NIL) { + + /* the subexpression matched */ + matched = 1; + s = ptr; + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + matched = 0; + } else if (*cs & OPT) { + + /* the match is optional */ + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + cs = OPTR(cs); + break; + } + break; + + /* try to match a metasymbol */ + case META: + switch (MSYM(cs)) { + + /* try to match anything and remember what was matched */ + case 'p': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + ptr = expmatch (s1, MNEXT(cs), mstring); + if (ptr != NIL && s1 != s) { + + /* we have a match, remember the match */ + strncpy (mstring, s, s1 - s); + mstring[s1 - s] = '\0'; + return (ptr); + } else if (ptr != NIL && (*cs & OPT)) { + + /* it was aoptional so no match is ok */ + return (ptr); + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (!isalnum(*s1) && *s1 != '_') + return (NIL); + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* try to match anything */ + case 'a': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + ptr = expmatch (s1, MNEXT(cs), mstring); + if (ptr != NIL && s1 != s) { + + /* we have a match */ + return (ptr); + } else if (ptr != NIL && (*cs & OPT)) { + + /* it was aoptional so no match is ok */ + return (ptr); + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* fail if we are currently _escaped */ + case 'e': + if (_escaped) + return(NIL); + cs = MNEXT(cs); + break; + + /* match any number of tabs and spaces */ + case 'd': + ptr = s; + while (*s == ' ' || *s == '\t') + s++; + if (s != ptr || s == _start) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*s == '\n' || *s == '\0') { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for end of line */ + case '$': + if (*s == '\0' || *s == '\n') { + + /* match, be happy */ + s++; + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for start of line */ + case '^': + if (s == _start) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* end of a subexpression, return success */ + case ')': + return (s); + } + break; + } + } + return (s); +} diff --git a/usr.bin/vgrind/tmac.vgrind b/usr.bin/vgrind/tmac.vgrind new file mode 100644 index 0000000..d9d8af2 --- /dev/null +++ b/usr.bin/vgrind/tmac.vgrind @@ -0,0 +1,68 @@ +'ss 23 +'ds _ \d\(mi\u +'ps 9p +'vs 10p +'ds - \(mi +'ds / \\h'\\w' 'u-\\w'/'u'/ +'ds /* \\h'\\w' 'u-\\w'/'u'/* +'bd B 3 +'bd S B 3 +'nr cm 0 +'nf +'de vH +'ev 2 +'if t 'if !\nv 'tl '\-\-''\-\-' +'ft 1 +'sp .35i +'tl '\s14\f3\\*(=F\fP\s0'\\*(=H'\f3\s14\\*(=F\fP\s0' +'sp .25i +'ft 1 +\f2\s12\h'\\n(.lu-\w'\\*(=f'u'\\*(=f\fP\s0\h'|0u' +.sp .05i +'ev +'ds =G \\*(=F +.. +'de vF +'ev 2 +'sp .35i +'ie o 'tl '\f2\\*(=M''Page % of \\*(=G\fP' +'el 'tl '\f2Page % of \\*(=G''\\*(=M\fP' +'bp +'ev +'ft 1 +'if \\n(cm=1 'ft 2 +.. +'de () +'pn 1 +.. +'de +C +'nr cm 1 +'ft 2 +'ds +K +'ds -K +.. +'de -C +'nr cm 0 +'ft 1 +'ds +K \f3 +'ds -K \fP +.. +'+C +'-C +'am +C +'ne 3 +.. +'de FN +\f2\s14\h'\\n(.lu-\w'\\$1'u'\\$1\fP\s0\h'|0u'\c +.if \\nx .tm \\$1 \\*(=F \\n% +'ds =f \&...\\$1 +.. +'de FC +.if \\nx .tm \\$1 \\*(=F \\n% +'ds =f \&...\\$1 +.. +'de -F +'rm =f +.. +'ft 1 +'lg 0 diff --git a/usr.bin/vgrind/vfontedpr.c b/usr.bin/vgrind/vfontedpr.c new file mode 100644 index 0000000..30320c6 --- /dev/null +++ b/usr.bin/vgrind/vfontedpr.c @@ -0,0 +1,705 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)vfontedpr.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" +#include "extern.h" + +#define FALSE 0 +#define TRUE !(FALSE) +#define NIL 0 +#define STANDARD 0 +#define ALTERNATE 1 + +/* + * Vfontedpr. + * + * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy) + * + */ + +#define STRLEN 10 /* length of strings introducing things */ +#define PNAMELEN 40 /* length of a function/procedure name */ +#define PSMAX 20 /* size of procedure name stacking */ + +static int iskw __P((char *)); +static boolean isproc __P((char *)); +static void putKcp __P((char *, char *, boolean)); +static void putScp __P((char *)); +static void putcp __P((int)); +static int tabs __P((char *, char *)); +static int width __P((char *, char *)); + +/* + * The state variables + */ + +static boolean filter = FALSE; /* act as a filter (like eqn) */ +static boolean inchr; /* in a string constant */ +static boolean incomm; /* in a comment of the primary type */ +static boolean idx = FALSE; /* form an index */ +static boolean instr; /* in a string constant */ +static boolean nokeyw = FALSE; /* no keywords being flagged */ +static boolean pass = FALSE; /* + * when acting as a filter, pass indicates + * whether we are currently processing + * input. + */ + +static int blklevel; /* current nesting level */ +static int comtype; /* type of comment */ +static char *defsfile[2] = { _PATH_VGRINDEFS, 0 }; + /* name of language definitions file */ +static int margin; +static int plstack[PSMAX]; /* the procedure nesting level stack */ +static char pname[BUFSIZ+1]; +static boolean prccont; /* continue last procedure */ +static int psptr; /* the stack index of the current procedure */ +static char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */ + +/* + * The language specific globals + */ + +char *l_acmbeg; /* string introducing a comment */ +char *l_acmend; /* string ending a comment */ +char *l_blkbeg; /* string begining of a block */ +char *l_blkend; /* string ending a block */ +char *l_chrbeg; /* delimiter for character constant */ +char *l_chrend; /* delimiter for character constant */ +char *l_combeg; /* string introducing a comment */ +char *l_comend; /* string ending a comment */ +char l_escape; /* character used to escape characters */ +char *l_keywds[BUFSIZ/2]; /* keyword table address */ +char *l_prcbeg; /* regular expr for procedure begin */ +char *l_strbeg; /* delimiter for string constant */ +char *l_strend; /* delimiter for string constant */ +boolean l_toplex; /* procedures only defined at top lex level */ +char *language = "c"; /* the language indicator */ + +#define ps(x) printf("%s", x) + +void +main(argc, argv) + int argc; + char *argv[]; +{ + char *fname = ""; + struct stat stbuf; + char buf[BUFSIZ]; + char *defs; + int needbp = 0; + + argc--, argv++; + do { + char *cp; + int i; + + if (argc > 0) { + if (!strcmp(argv[0], "-h")) { + if (argc == 1) { + printf("'ds =H\n"); + argc = 0; + goto rest; + } + printf("'ds =H %s\n", argv[1]); + argc--, argv++; + argc--, argv++; + if (argc > 0) + continue; + goto rest; + } + + /* act as a filter like eqn */ + if (!strcmp(argv[0], "-f")) { + filter++; + argv[0] = argv[argc-1]; + argv[argc-1] = "-"; + continue; + } + + /* take input from the standard place */ + if (!strcmp(argv[0], "-")) { + argc = 0; + goto rest; + } + + /* build an index */ + if (!strcmp(argv[0], "-x")) { + idx++; + argv[0] = "-n"; + } + + /* indicate no keywords */ + if (!strcmp(argv[0], "-n")) { + nokeyw++; + argc--, argv++; + continue; + } + + /* specify the font size */ + if (!strncmp(argv[0], "-s", 2)) { + i = 0; + cp = argv[0] + 2; + while (*cp) + i = i * 10 + (*cp++ - '0'); + printf("'ps %d\n'vs %d\n", i, i+1); + argc--, argv++; + continue; + } + + /* specify the language */ + if (!strncmp(argv[0], "-l", 2)) { + language = argv[0]+2; + argc--, argv++; + continue; + } + + /* specify the language description file */ + if (!strncmp(argv[0], "-d", 2)) { + defsfile[0] = argv[1]; + argc--, argv++; + argc--, argv++; + continue; + } + + /* open the file for input */ + if (freopen(argv[0], "r", stdin) == NULL) { + perror(argv[0]); + exit(1); + } + if (idx) + printf("'ta 4i 4.25i 5.5iR\n'in .5i\n"); + fname = argv[0]; + argc--, argv++; + } + rest: + + /* + * get the language definition from the defs file + */ + i = cgetent(&defs, defsfile, language); + if (i == -1) { + fprintf (stderr, "no entry for language %s\n", language); + exit (0); + } else if (i == -2) { fprintf(stderr, + "cannot find vgrindefs file %s\n", defsfile[0]); + exit (0); + } else if (i == -3) { fprintf(stderr, + "potential reference loop detected in vgrindefs file %s\n", + defsfile[0]); + exit(0); + } + if (cgetustr(defs, "kw", &cp) == -1) + nokeyw = TRUE; + else { + char **cpp; + + cpp = l_keywds; + while (*cp) { + while (*cp == ' ' || *cp =='\t') + *cp++ = NULL; + if (*cp) + *cpp++ = cp; + while (*cp != ' ' && *cp != '\t' && *cp) + cp++; + } + *cpp = NIL; + } + cgetustr(defs, "pb", &cp); + l_prcbeg = convexp(cp); + cgetustr(defs, "cb", &cp); + l_combeg = convexp(cp); + cgetustr(defs, "ce", &cp); + l_comend = convexp(cp); + cgetustr(defs, "ab", &cp); + l_acmbeg = convexp(cp); + cgetustr(defs, "ae", &cp); + l_acmend = convexp(cp); + cgetustr(defs, "sb", &cp); + l_strbeg = convexp(cp); + cgetustr(defs, "se", &cp); + l_strend = convexp(cp); + cgetustr(defs, "bb", &cp); + l_blkbeg = convexp(cp); + cgetustr(defs, "be", &cp); + l_blkend = convexp(cp); + cgetustr(defs, "lb", &cp); + l_chrbeg = convexp(cp); + cgetustr(defs, "le", &cp); + l_chrend = convexp(cp); + l_escape = '\\'; + l_onecase = (cgetcap(defs, "oc", ':') != NULL); + l_toplex = (cgetcap(defs, "tl", ':') != NULL); + + /* initialize the program */ + + incomm = FALSE; + instr = FALSE; + inchr = FALSE; + _escaped = FALSE; + blklevel = 0; + for (psptr=0; psptr= 0)) { + ps("'FC "); + ps(pstack[psptr]); + ps("\n"); + } +#ifdef DEBUG + printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); +#endif + margin = 0; + } + needbp = 1; + } while (argc > 0); + exit(0); +} + +#define isidchr(c) (isalnum(c) || (c) == '_') + +static void +putScp(os) + char *os; +{ + register char *s = os; /* pointer to unmatched string */ + char dummy[BUFSIZ]; /* dummy to be used by expmatch */ + char *comptr; /* end of a comment delimiter */ + char *acmptr; /* end of a comment delimiter */ + char *strptr; /* end of a string delimiter */ + char *chrptr; /* end of a character const delimiter */ + char *blksptr; /* end of a lexical block start */ + char *blkeptr; /* end of a lexical block end */ + + _start = os; /* remember the start for expmatch */ + _escaped = FALSE; + if (nokeyw || incomm || instr) + goto skip; + if (isproc(s)) { + ps("'FN "); + ps(pname); + ps("\n"); + if (psptr < PSMAX) { + ++psptr; + strncpy (pstack[psptr], pname, PNAMELEN); + pstack[psptr][PNAMELEN] = NULL; + plstack[psptr] = blklevel; + } + } +skip: + do { + /* check for string, comment, blockstart, etc */ + if (!incomm && !instr && !inchr) { + + blkeptr = expmatch (s, l_blkend, dummy); + blksptr = expmatch (s, l_blkbeg, dummy); + comptr = expmatch (s, l_combeg, dummy); + acmptr = expmatch (s, l_acmbeg, dummy); + strptr = expmatch (s, l_strbeg, dummy); + chrptr = expmatch (s, l_chrbeg, dummy); + + /* start of a comment? */ + if (comptr != NIL) + if ((comptr < strptr || strptr == NIL) + && (comptr < acmptr || acmptr == NIL) + && (comptr < chrptr || chrptr == NIL) + && (comptr < blksptr || blksptr == NIL) + && (comptr < blkeptr || blkeptr == NIL)) { + putKcp (s, comptr-1, FALSE); + s = comptr; + incomm = TRUE; + comtype = STANDARD; + if (s != os) + ps ("\\c"); + ps ("\\c\n'+C\n"); + continue; + } + + /* start of a comment? */ + if (acmptr != NIL) + if ((acmptr < strptr || strptr == NIL) + && (acmptr < chrptr || chrptr == NIL) + && (acmptr < blksptr || blksptr == NIL) + && (acmptr < blkeptr || blkeptr == NIL)) { + putKcp (s, acmptr-1, FALSE); + s = acmptr; + incomm = TRUE; + comtype = ALTERNATE; + if (s != os) + ps ("\\c"); + ps ("\\c\n'+C\n"); + continue; + } + + /* start of a string? */ + if (strptr != NIL) + if ((strptr < chrptr || chrptr == NIL) + && (strptr < blksptr || blksptr == NIL) + && (strptr < blkeptr || blkeptr == NIL)) { + putKcp (s, strptr-1, FALSE); + s = strptr; + instr = TRUE; + continue; + } + + /* start of a character string? */ + if (chrptr != NIL) + if ((chrptr < blksptr || blksptr == NIL) + && (chrptr < blkeptr || blkeptr == NIL)) { + putKcp (s, chrptr-1, FALSE); + s = chrptr; + inchr = TRUE; + continue; + } + + /* end of a lexical block */ + if (blkeptr != NIL) { + if (blkeptr < blksptr || blksptr == NIL) { + putKcp (s, blkeptr - 1, FALSE); + s = blkeptr; + blklevel--; + if (psptr >= 0 && plstack[psptr] >= blklevel) { + + /* end of current procedure */ + if (s != os) + ps ("\\c"); + ps ("\\c\n'-F\n"); + blklevel = plstack[psptr]; + + /* see if we should print the last proc name */ + if (--psptr >= 0) + prccont = TRUE; + else + psptr = -1; + } + continue; + } + } + + /* start of a lexical block */ + if (blksptr != NIL) { + putKcp (s, blksptr - 1, FALSE); + s = blksptr; + blklevel++; + continue; + } + + /* check for end of comment */ + } else if (incomm) { + comptr = expmatch (s, l_comend, dummy); + acmptr = expmatch (s, l_acmend, dummy); + if (((comtype == STANDARD) && (comptr != NIL)) || + ((comtype == ALTERNATE) && (acmptr != NIL))) { + if (comtype == STANDARD) { + putKcp (s, comptr-1, TRUE); + s = comptr; + } else { + putKcp (s, acmptr-1, TRUE); + s = acmptr; + } + incomm = FALSE; + ps("\\c\n'-C\n"); + continue; + } else { + putKcp (s, s + strlen(s) -1, TRUE); + s = s + strlen(s); + continue; + } + + /* check for end of string */ + } else if (instr) { + if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { + putKcp (s, strptr-1, TRUE); + s = strptr; + instr = FALSE; + continue; + } else { + putKcp (s, s+strlen(s)-1, TRUE); + s = s + strlen(s); + continue; + } + + /* check for end of character string */ + } else if (inchr) { + if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { + putKcp (s, chrptr-1, TRUE); + s = chrptr; + inchr = FALSE; + continue; + } else { + putKcp (s, s+strlen(s)-1, TRUE); + s = s + strlen(s); + continue; + } + } + + /* print out the line */ + putKcp (s, s + strlen(s) -1, FALSE); + s = s + strlen(s); + } while (*s); +} + +static void +putKcp (start, end, force) + char *start; /* start of string to write */ + char *end; /* end of string to write */ + boolean force; /* true if we should force nokeyw */ +{ + int i; + int xfld = 0; + + while (start <= end) { + if (idx) { + if (*start == ' ' || *start == '\t') { + if (xfld == 0) + printf(""); + printf("\t"); + xfld = 1; + while (*start == ' ' || *start == '\t') + start++; + continue; + } + } + + /* take care of nice tab stops */ + if (*start == '\t') { + while (*start == '\t') + start++; + i = tabs(_start, start) - margin / 8; + printf("\\h'|%dn'", i * 10 + 1 - margin % 8); + continue; + } + + if (!nokeyw && !force) + if ((*start == '#' || isidchr(*start)) + && (start == _start || !isidchr(start[-1]))) { + i = iskw(start); + if (i > 0) { + ps("\\*(+K"); + do + putcp(*start++); + while (--i > 0); + ps("\\*(-K"); + continue; + } + } + + putcp (*start++); + } +} + + +static int +tabs(s, os) + char *s, *os; +{ + + return (width(s, os) / 8); +} + +static int +width(s, os) + register char *s, *os; +{ + register int i = 0; + + while (s < os) { + if (*s == '\t') { + i = (i + 8) &~ 7; + s++; + continue; + } + if (*s < ' ') + i += 2; + else + i++; + s++; + } + return (i); +} + +static void +putcp(c) + register int c; +{ + + switch(c) { + + case 0: + break; + + case '\f': + break; + + case '{': + ps("\\*(+K{\\*(-K"); + break; + + case '}': + ps("\\*(+K}\\*(-K"); + break; + + case '\\': + ps("\\e"); + break; + + case '_': + ps("\\*_"); + break; + + case '-': + ps("\\*-"); + break; + + case '`': + ps("\\`"); + break; + + case '\'': + ps("\\'"); + break; + + case '.': + ps("\\&."); + break; + + case '*': + ps("\\fI*\\fP"); + break; + + case '/': + ps("\\fI\\h'\\w' 'u-\\w'/'u'/\\fP"); + break; + + default: + if (c < 040) + putchar('^'), c |= '@'; + case '\t': + case '\n': + putchar(c); + } +} + +/* + * look for a process beginning on this line + */ +static boolean +isproc(s) + char *s; +{ + pname[0] = NULL; + if (!l_toplex || blklevel == 0) + if (expmatch (s, l_prcbeg, pname) != NIL) { + return (TRUE); + } + return (FALSE); +} + + +/* iskw - check to see if the next word is a keyword + */ + +static int +iskw(s) + register char *s; +{ + register char **ss = l_keywds; + register int i = 1; + register char *cp = s; + + while (++cp, isidchr(*cp)) + i++; + while (cp = *ss++) + if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) + return (i); + return (0); +} + diff --git a/usr.bin/vgrind/vgrind.1 b/usr.bin/vgrind/vgrind.1 new file mode 100644 index 0000000..97ba7e2 --- /dev/null +++ b/usr.bin/vgrind/vgrind.1 @@ -0,0 +1,224 @@ +.\" Copyright (c) 1980, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vgrind.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt VGRIND 1 +.Os BSD 4 +.Sh NAME +.Nm vgrind +.Nd grind nice listings of programs +.Sh SYNOPSIS +.Nm vgrind +.Op Fl +.Op Fl W +.Op Fl d Ar file +.Op Fl f +.Op Fl h Ar header +.Op Fl l Ar language +.Op Fl n +.Op Fl sn +.Op Fl t +.Op Fl x +.Ar name Ar ... +.Sh DESCRIPTION +.Nm Vgrind +formats the program sources which are arguments +in a nice style using +.Xr troff 1 +Comments are placed in italics, keywords in bold face, +and the name of the current function is listed down the margin of each +page as it is encountered. +.Pp +.Nm Vgrind +runs in two basic modes, filter mode (see the +.Fl f +option) or regular mode. In filter mode +.Nm vgrind +acts as a filter in a manner similar to +.Xr tbl 1 . +The standard input is passed directly to the standard output except +for lines bracketed by the +.Em troff-like +macros: +.Bl -tag -width Ds +.It \&.vS +starts processing +.It \&.vE +ends processing +.El +.Pp +These lines are formatted as described above. The output from this +filter can be passed to +.Xr troff +for output. There need be no particular ordering with +.Xr eqn 1 +or +.Xr tbl 1 . +.Pp +In regular mode +.Nm vgrind +accepts input files, processes them, and passes them to +.Xr troff 1 +for output. +.Pp +In both modes +.Nm vgrind +passes any lines beginning with a decimal point without conversion. +.Pp +The options are: +.Bl -tag -width Ar +.It Fl +forces input to be taken from standard input (default if +.Fl f +is specified ) +.It Fl W +forces output to the (wide) Versatec printer rather than the (narrow) +Varian +.It Fl d Ar file +specifies an alternate language definitions +file (default is +.Pa /usr/share/misc/vgrindefs ) +.It Fl f +forces filter mode +.It Fl h Ar header +specifies a particular header to put on every output page (default is +the file name) +.It Fl l +specifies the language to use. Currently known are +.Tn PASCAL +.Pq Fl l Ns Ar p , +.Tn MODEL +.Pq Fl l Ns Ar m , +C +.Pf ( Fl l Ns Ar c +or the default), +.Tn CSH +.Pq Fl l Ns Ar csh , +.Tn SHELL +.Pq Fl l Ns Ar sh , +.Tn RATFOR +.Pq Fl l Ns Ar r , +.Tn MODULA2 +.Pq Fl l Ns Ar mod2 , +.Tn YACC +.Pq Fl l Ns Ar yacc , +.Tn LISP +.Pq Fl l Ns Ar isp , +and +.Tn ICON +.Pq Fl l Ns Ar I . +.It Fl n +forces no keyword bolding +.It Fl s +specifies a point size to use on output (exactly the same as the argument +of a .ps) +.It Fl t +similar to the same option in +.Xr troff +causing formatted text to go to the standard output +.It Fl x +outputs the index file in a ``pretty'' format. +The index file itself is produced whenever +.Nm vgrind +is run with a file called +.Pa index +in the current directory. +The index of function +definitions can then be run off by giving +.Nm vgrind +the +.Fl x +option and the file +.Pa index +as argument. +.El +.Sh FILES +.Bl -tag -width /usr/share/misc/vgrindefsxx -compact +.It Pa index +file where source for index is created +.It Pa /usr/share/tmac/tmac.vgrind +macro package +.It Pa /usr/libexec/vfontedpr +preprocessor +.It Pa /usr/share/misc/vgrindefs +language descriptions +.El +.Sh SEE ALSO +.Xr getcap 3 , +.Xr vgrindefs 5 +.Sh BUGS +Vfontedpr assumes that a certain programming style is followed: +.Pp +For +.Tn C +\- function names can be preceded on a line only by spaces, tabs, or an +asterisk. The parenthesized arguments must also be on the same line. +.Pp +For +.Tn PASCAL +\- function names need to appear on the same line as the keywords +.Em function +or +.Em procedure . +.Pp +For +.Tn MODEL +\- function names need to appear on the same line as the keywords +.Em is beginproc . +.Pp +If these conventions are not followed, the indexing and marginal function +name comment mechanisms will fail. +.Pp +More generally, arbitrary formatting styles for programs mostly look bad. +The use of spaces to align source code fails miserably; if you plan to +.Nm vgrind +your program you should use tabs. This is somewhat inevitable since the +font used by +.Nm vgrind +is variable width. +.Pp +The mechanism of +.Xr ctags 1 +in recognizing functions should be used here. +.Pp +Filter mode does not work in documents using the +.Fl me +or +.Fl ms +macros. +(So what use is it anyway?) +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/vgrind/vgrind.sh b/usr.bin/vgrind/vgrind.sh new file mode 100644 index 0000000..fc05461 --- /dev/null +++ b/usr.bin/vgrind/vgrind.sh @@ -0,0 +1,143 @@ +#!/bin/csh -f +# +# 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. +# +# @(#)vgrind.sh 8.1 (Berkeley) 6/6/93 +# + +set voptions= +set options= +set files= +set f='' +set head="" +set vf=/usr/libexec/vfontedpr +set tm=/usr/share/tmac +top: +if ($#argv > 0) then + switch ($1:q) + + case -f: + set f='filter' + set options = "$options $1:q" + shift + goto top + + case -t: + set voptions = "$voptions -t" + shift + goto top + + case -o*: + set voptions="$voptions $1:q" + shift + goto top + + case -W: + set voptions = "$voptions -W" + shift + goto top + + case -d: + if ($#argv < 2) then + echo "vgrind: $1:q option must have argument" + goto done + else + set options = ($options $1:q $2) + shift + shift + goto top + endif + + case -h: + if ($#argv < 2) then + echo "vgrind: $1:q option must have argument" + goto done + else + set head="$2" + shift + shift + goto top + endif + + case -*: + set options = "$options $1:q" + shift + goto top + + default: + set files = "$files $1:q" + shift + goto top + endsw +endif +if (-r index) then + echo > nindex + foreach i ($files) + # make up a sed delete command for filenames + # being careful about slashes. + echo "? $i ?d" | sed -e "s:/:\\/:g" -e "s:?:/:g" >> nindex + end + sed -f nindex index >xindex + if ($f == 'filter') then + if ("$head" != "") then + $vf $options -h "$head" $files | cat $tm/tmac.vgrind - + else + $vf $options $files | cat $tm/tmac.vgrind - + endif + else + if ("$head" != "") then + $vf $options -h "$head" $files | \ + sh -c "psroff -rx1 $voptions -i -mvgrind 2>> xindex" + else + $vf $options $files | \ + sh -c "psroff -rx1 $voptions -i -mvgrind 2>> xindex" + endif + endif + sort -df +0 -2 xindex >index + rm nindex xindex +else + if ($f == 'filter') then + if ("$head" != "") then + $vf $options -h "$head" $files | cat $tm/tmac.vgrind - + else + $vf $options $files | cat $tm/tmac.vgrind - + endif + else + if ("$head" != "") then + $vf $options -h "$head" $files | psroff -i $voptions -mvgrind + else + $vf $options $files | psroff -i $voptions -mvgrind + endif + endif +endif + +done: diff --git a/usr.bin/vgrind/vgrindefs.5 b/usr.bin/vgrind/vgrindefs.5 new file mode 100644 index 0000000..4ac7522 --- /dev/null +++ b/usr.bin/vgrind/vgrindefs.5 @@ -0,0 +1,158 @@ +.\" Copyright (c) 1989, 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. +.\" +.\" @(#)vgrindefs.5 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt VGRINDEFS 5 +.Os BSD 4.2 +.Sh NAME +.Nm vgrindefs +.Nd language definition data base for +.Xr vgrind 1 +.Sh SYNOPSIS +.Nm vgrindefs +.Sh DESCRIPTION +The +.Nm vgrindefs +file +contains all language definitions for +.Xr vgrind 1 . +The data base is +very similar to +.Xr termcap 5 . +.Sh FIELDS +The following table names and describes each field. +.Pp +.Bl -column Namexxx Tpexxx +.Sy Name Type Description +.It "pb str regular expression for start of a procedure" +.It "bb str regular expression for start of a lexical block" +.It "be str regular expression for the end of a lexical block" +.It "cb str regular expression for the start of a comment" +.It "ce str regular expression for the end of a comment" +.It "sb str regular expression for the start of a string" +.It "se str regular expression for the end of a string" +.It "lb str regular expression for the start of a character constant" +.It "le str regular expression for the end of a character constant" +.It "tl bool present means procedures are only defined at the top lexical level" +.It "oc bool present means upper and lower case are equivalent" +.It "kw str a list of keywords separated by spaces" +.El +.Pp +.Sh EXAMPLES +The following entry, which describes the C language, is +typical of a language entry. +.Bd -literal +C|c:\ +:pb=^\ed?*?\ed?\ep\ed?\e(\ea?\e):bb={:be=}:cb=/*:ce=*/:sb=":se=\ee":\e +:lb=':le=\ee':tl:\e +:kw=asm auto break case char continue default do double else enum\e +extern float for fortran goto if int long register return short\e +sizeof static struct switch typedef union unsigned while #define\e +#else #endif #if #ifdef #ifndef #include #undef # define else endif\e +if ifdef ifndef include undef: +.Ed +.Pp +Note that the first field is just the language name (and any variants +of it). Thus the C language could be specified to +.Xr vgrind 1 +as "c" or "C". +.Pp +Entries may continue onto multiple lines by giving a \e as the last +character of a line. +Capabilities in +.Nm vgrindefs +are of two types: +Boolean capabilities which indicate that the language has +some particular feature +and string +capabilities which give a regular expression or +keyword list. +.Sh REGULAR EXPRESSIONS +.Nm Vgrindefs +uses regular expression which are very similar to those of +.Xr ex 1 +and +.Xr lex 1 . +The characters `^', `$', `:' and `\e' +are reserved characters and must be +"quoted" with a preceding +.Ql \e +if they +are to be included as normal characters. +The metasymbols and their meanings are: +.Bl -tag -width indent +.It $ +the end of a line +.It \&^ +the beginning of a line +.It \ed +a delimiter (space, tab, newline, start of line) +.It \ea +matches any string of symbols (like .* in lex) +.It \ep +matches any alphanumeric name. In a procedure definition (pb) the string +that matches this symbol is used as the procedure name. +.It () +grouping +.It \&| +alternation +.It ? +last item is optional +.It \ee +preceding any string means that the string will not match an +input string if the input string is preceded by an escape character (\e). +This is typically used for languages (like C) which can include the +string delimiter in a string by escaping it. +.El +.Pp +Unlike other regular expressions in the system, these match words +and not characters. Hence something like "(tramp|steamer)flies?" +would match "tramp", "steamer", "trampflies", or "steamerflies". +.Sh KEYWORD LIST +The keyword list is just a list of keywords in the language separated +by spaces. If the "oc" boolean is specified, indicating that upper +and lower case are equivalent, then all the keywords should be +specified in lower case. +.Sh FILES +.Bl -tag -width /usr/share/misc/vgrindefs -compact +.It Pa /usr/share/misc/vgrindefs +File containing terminal descriptions. +.El +.Sh SEE ALSO +.Xr vgrind 1 , +.Xr troff 1 +.Sh HISTORY +The +.Nm +file format appeared in +.Bx 4.2 . diff --git a/usr.bin/vgrind/vgrindefs.c b/usr.bin/vgrind/vgrindefs.c new file mode 100644 index 0000000..23f06bd --- /dev/null +++ b/usr.bin/vgrind/vgrindefs.c @@ -0,0 +1,326 @@ +/* + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)vgrindefs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#define BUFSIZ 1024 +#define MAXHOP 32 /* max number of tc= indirections */ + +#include +/* + * grindcap - routines for dealing with the language definitions data base + * (code stolen almost totally from termcap) + * + * BUG: Should use a "last" pointer in tbuf, so that searching + * for capabilities alphabetically would not be a n**2/2 + * process when large numbers of capabilities are given. + * Note: If we add a last pointer now we will screw up the + * tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities. We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static char *tbuf; +static char *filename; +static int hopcount; /* detect infinite loops in termcap, init 0 */ +char *tskip(); +char *tgetstr(); +char *tdecode(); +char *getenv(); + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +tgetent(bp, name, file) + char *bp, *name, *file; +{ + register char *cp; + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ]; + char *cp2; + int tf; + + tbuf = bp; + tf = 0; + filename = file; + tf = open(filename, 0); + if (tf < 0) + return (-1); + for (;;) { + cp = bp; + for (;;) { + if (i == cnt) { + cnt = read(tf, ibuf, BUFSIZ); + if (cnt <= 0) { + close(tf); + return (0); + } + i = 0; + } + c = ibuf[i++]; + if (c == '\n') { + if (cp > bp && cp[-1] == '\\'){ + cp--; + continue; + } + break; + } + if (cp >= bp+BUFSIZ) { + write(2,"Vgrind entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return(tnchktc()); + } + } +} + +/* + * tnchktc: check the last entry, see if it's tc=xxx. If so, + * recursively find xxx and append that entry (minus the names) + * to take the place of the tc=xxx entry. This allows termcap + * entries to say "like an HP2621 but doesn't turn on the labels". + * Note that this works because of the left to right scan. + */ +tnchktc() +{ + register char *p, *q; + char tcname[16]; /* name of similar terminal */ + char tcbuf[BUFSIZ]; + char *holdtbuf = tbuf; + int l; + + p = tbuf + strlen(tbuf) - 2; /* before the last colon */ + while (*--p != ':') + if (p MAXHOP) { + write(2, "Infinite tc= loop\n", 18); + return (0); + } + if (tgetent(tcbuf, tcname, filename) != 1) + return(0); + for (q=tcbuf; *q != ':'; q++) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Vgrind entry too long\n", 23); + q[BUFSIZ - (p-tbuf)] = 0; + } + strcpy(p, q+1); + tbuf = holdtbuf; + return(1); +} + +/* + * Tnamatch deals with name matching. The first field of the termcap + * entry is a sequence of names separated by |'s, so we compare + * against each such name. The normal : terminator after the last + * name (before the first field) stops us. + */ +tnamatch(np) + char *np; +{ + register char *Np, *Bp; + + Bp = tbuf; + if (*Bp == '#') + return(0); + for (;;) { + for (Np = np; *Np && *Bp == *Np; Bp++, Np++) + continue; + if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) + return (1); + while (*Bp && *Bp != ':' && *Bp != '|') + Bp++; + if (*Bp == 0 || *Bp == ':') + return (0); + Bp++; + } +} + +/* + * Skip to the next field. Notice that this is very dumb, not + * knowing about \: escapes or any such. If necessary, :'s can be put + * into the termcap file in octal. + */ +static char * +tskip(bp) + register char *bp; +{ + + while (*bp && *bp != ':') + bp++; + if (*bp == ':') + bp++; + return (bp); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + * li#80 + * i.e. the option string is separated from the numeric value by + * a # character. If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +tgetnum(id) + char *id; +{ + register int i, base; + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (*bp == 0) + return (-1); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return(-1); + if (*bp != '#') + continue; + bp++; + base = 10; + if (*bp == '0') + base = 8; + i = 0; + while (isdigit(*bp)) + i *= base, i += *bp++ - '0'; + return (i); + } +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer. Return 1 if we find the option, or 0 if it is + * not given. + */ +tgetflag(id) + char *id; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { + if (!*bp || *bp == ':') + return (1); + else if (*bp == '@') + return(0); + } + } +} + +/* + * Get a string valued option. + * These are given as + * cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) + char *id, **area; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return(0); + if (*bp != '=') + continue; + bp++; + return (tdecode(bp, area)); + } +} + +/* + * Tdecode does the grung work to decode the + * string capability escapes. + */ +static char * +tdecode(str, area) + register char *str; + char **area; +{ + register char *cp; + register int c; + int i; + + cp = *area; + while (c = *str++) { + if (c == ':' && *(cp-1) != '\\') + break; + *cp++ = c; + } + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} diff --git a/usr.bin/vgrind/vgrindefs.src b/usr.bin/vgrind/vgrindefs.src new file mode 100644 index 0000000..91ef58f --- /dev/null +++ b/usr.bin/vgrind/vgrindefs.src @@ -0,0 +1,146 @@ +# Copyright (c) 1987, 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. +# +# @(#)vgrindefs.src 8.1 (Berkeley) 6/6/93 +# + +C|c:\ + :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:cb=/*:ce=*/:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=asm auto break case char continue default do double else enum\ + extern float for fortran goto if int long register return short\ + sizeof static struct switch typedef union unsigned void while #define\ + #else #endif #if #ifdef #ifndef #include #undef # define else endif\ + if ifdef ifndef include undef: +model|mod|m:\ + :pb=^\d(space\d\p\drep)|(\p\dis|inline|public\dbeginproc):\ + :bb=\dbeginproc|space|case\d:be=\dendproc|end\d|;:\ + :cb=\$:ce=\$|$:sb=":se=":lb=':le=\a|$:\ + :kw=abs and array beginproc boolean by case cdnl char copied dispose\ + div do dynamic else elsif end endproc entry external FALSE false\ + fi file for formal fortran global if iff ift\ + in integer include inline is lbnd\ + max min mod new NIL nil noresult not notin od of or procedure public\ + read readln readonly record recursive rem rep repeat res\ + result return set\ + space string subscript such then TRUE true type ubnd union until\ + varies while width: +pascal|pasc|p:\ + :pb=(^\d?procedure|function|program\d\p\d|\(|;|\:)|(=\d?record\d):\ + :bb=\dcase|begin\d:be=\dend|forward\d|;:\ + :cb={:ce=}:\ + :ab=\(*:ae=*\):\ + :sb=':se=':\ + :kw=and array assert begin case const div do downto else end file for\ + forward function goto if in label mod nil not of or packed procedure\ + program record repeat set then to type until var while with oct hex\ + external: +ISP|isp|i:\ + :cb=!:ce=!|$:oc:\ + :kw=and begin decode define end eql eqv geq gtr if leave leq lss mod\ + neq next not or otherwise repeat restart resume sr0 sr1 srd srr sl0 sl1\ + sld slr tst xor: +SH|sh:\ + :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=break case cd continue do done \ + elif else esac eval exec exit export \ + fi for if in then while until \ + read readonly set shift test trap umask wait: +CSH|csh:\ + :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=alias alloc break breaksw case cd chdir continue default\ + echo else end endif endsw exec exit foreach \ + glob goto history if logout nice nohup onintr repeat set\ + setenv shift source switch then time \ + while umask unalias unset wait while @ env \ + argv child home ignoreeof noclobber noglob \ + nomatch path prompt shell status verbose : +ldl|LDL:\ + :pb=^\p\::bb=\::be=;:cb=/*:ce=*/:sb=":se=\e":\ + :kw=constant functions grammar reswords tokens add1 addste\ + car cdr check colno cond cons copy defun divide empty enter\ + eq equal findattr firstchild ge getattr getfield gt hash label\ + lambda lastchild le leftsibling lookone lookup lt minus name ne\ + newnode nextcom nil null parent plus precnl prevcom prog progn\ + quote reglob return rightsibling self set setattr setfield setq\ + stjoin sub1 t times tnull tokno ttype: +Icon|icon|I:\ + :pb=^\d?procedure\d\p\d?\(\a?\):\ + :bb=(^\d?procedure\d\p\d?\(\a?\))|{:be=}|(^\d?end\d?$):\ + :cb=#:ce=$:\ + :sb=":se=\e":lb=':le=\e':tl:\ + :kw=break by case create default do dynamic else end every external\ + fail global if initial local next not of procedure record\ + repeat return static suspend then to until using while\ + &ascii &clock &cset &date &dateline &errout &fail &host &input\ + &lcase &level &main &null &output &pos &random &source &subject\ + &time &trace &ucase &version: +ratfor|rat|r:\ + :pb=(subroutine|function)\d\p\d?\(\a?\):\ + :bb=(subroutine|function)\d\p\d?\(\a?\):be=^\d?end:\ + :cb=#:ce=$:\ + :sb=":se=\e":lb=':le=\e':oc:\ + :kw=DRETURN DRIVER arith break case character default define do\ + else elsedef enddef filedes for function goto if ifdef ifelse\ + ifnotdef include incr integer linepointer next opeq pointer\ + real repeat return select string subroutine substr until: +modula2|mod2|m2:\ + :pb=(^\d?(procedure|function|module)\d\p\d|\(|;|\:):\ + :bb=\d(begin|case|for|if|loop|record|repeat|while|with)\d:\ + :be=\dend|;:\ + :cb={:ce=}:\ + :ab=\(*:ae=*\):\ + :sb=":se=":\ + :oc:\ + :kw=and array begin by case const\ + definition div do else elsif end exit export\ + for from if implementation import in\ + loop mod module not of or pointer procedure qualified\ + record repeat return set then to type\ + until var while with: +yacc|Yacc|y:\ + :cb=/*:ce=*/:sb=":se=\e":lb=':le=\e':tl:\ + :kw=%{ %} %% %union %token %type\ + #else #endif #if #ifdef #ifndef #include #undef # define else endif\ + if ifdef ifndef include undef: +C++|c++:\ + :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:cb=/*:ce=*/:ab=//:\ + :ae=$:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=asm auto break case char continue default do double else enum\ + extern float for fortran goto if int long register return short\ + sizeof static struct switch typedef union unsigned while void #define\ + #else #endif #if #ifdef #ifndef #include #undef # define endif\ + ifdef ifndef include undef defined\ + class const delete friend inline new operator overload private\ + protected public virtual: diff --git a/usr.bin/vis/Makefile b/usr.bin/vis/Makefile new file mode 100644 index 0000000..8f83a14 --- /dev/null +++ b/usr.bin/vis/Makefile @@ -0,0 +1,6 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= vis +SRCS= vis.c foldit.c + +.include diff --git a/usr.bin/vis/foldit.c b/usr.bin/vis/foldit.c new file mode 100644 index 0000000..2682e85 --- /dev/null +++ b/usr.bin/vis/foldit.c @@ -0,0 +1,72 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)foldit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +foldit(chunk, col, max) + char *chunk; +{ + register char *cp; + + /* + * Keep track of column position. Insert hidden newline + * if this chunk puts us over the limit. + */ +again: + cp = chunk; + while (*cp) { + switch(*cp) { + case '\n': + case '\r': + col = 0; + break; + case '\t': + col = col + 8 &~ 07; + break; + case '\b': + col = col ? col - 1 : 0; + break; + default: + col++; + } + if (col > (max - 2)) { + printf("\\\n"); + col = 0; + goto again; + } + cp++; + } + return (col); +} diff --git a/usr.bin/vis/vis.1 b/usr.bin/vis/vis.1 new file mode 100644 index 0000000..784e56c --- /dev/null +++ b/usr.bin/vis/vis.1 @@ -0,0 +1,124 @@ +.\" Copyright (c) 1989, 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. +.\" +.\" @(#)vis.1 8.4 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt VIS 1 +.Os BSD 4.4 +.Sh NAME +.Nm vis +.Nd display non-printable characters in a visual format +.Sh SYNOPSIS +.Nm vis +.Op Fl cbflnostw +.Op Fl F Ar foldwidth +.Op Ar file ... +.Sh DESCRIPTION +.Nm Vis +is a filter for converting non-printable characters +into a visual representation. It differs from +.Ql cat -v +in that +the form is unique and invertible. By default, all non-graphic +characters except space, tab, and newline are encoded. +A detailed description of the +various visual formats is given in +.Xr vis 3 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b +Turns off prepending of backslash before up-arrow control sequences +and meta characters, and disables the doubling of backslashes. This +produces output which is neither invertible or precise, but does +represent a minimum of change to the input. It is similar to +.Dq Li cat -v . +.It Fl c +Request a format which displays a small subset of the +non-printable characters using C-style backslash sequences. +.It Fl F +Causes +.Nm vis +to fold output lines to foldwidth columns (default 80), like +.Xr fold 1 , +except +that a hidden newline sequence is used, (which is removed +when inverting the file back to its original form with +.Xr unvis 1 ) . +If the last character in the encoded file does not end in a newline, +a hidden newline sequence is appended to the output. +This makes +the output usable with various editors and other utilities which +typically don't work with partial lines. +.It Fl f +Same as +.Fl F . +.It Fl l +Mark newlines with the visible sequence +.Ql \e$ , +followed by the newline. +.It Fl n +Turns off any encoding, except for the fact that backslashes are +still doubled and hidden newline sequences inserted if +.Fl f +or +.Fl F +is selected. When combined with the +.Fl f +flag, +.Nm vis +becomes like +an invertible version of the +.Xr fold 1 +utility. That is, the output +can be unfolded by running the output through +.It Fl o +Request a format which displays non-printable characters as +an octal number, \eddd. +.It Fl s +Only characters considered unsafe to send to a terminal are encoded. +This flag allows backspace, bell, and carriage return in addition +to the default space, tab and newline. +.Xr unvis 1 . +.It Fl t +Tabs are also encoded. +.It Fl w +White space (space-tab-newline) is also encoded. +.El +.Sh SEE ALSO +.Xr unvis 1 , +.Xr vis 3 +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/vis/vis.c b/usr.bin/vis/vis.c new file mode 100644 index 0000000..94c9d41 --- /dev/null +++ b/usr.bin/vis/vis.c @@ -0,0 +1,173 @@ +/*- + * Copyright (c) 1989, 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 copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include + +int eflags, fold, foldwidth=80, none, markeol, debug; + +main(argc, argv) + char *argv[]; +{ + extern char *optarg; + extern int optind; + extern int errno; + FILE *fp; + int ch; + + while ((ch = getopt(argc, argv, "nwctsobfF:ld")) != EOF) + switch((char)ch) { + case 'n': + none++; + break; + case 'w': + eflags |= VIS_WHITE; + break; + case 'c': + eflags |= VIS_CSTYLE; + break; + case 't': + eflags |= VIS_TAB; + break; + case 's': + eflags |= VIS_SAFE; + break; + case 'o': + eflags |= VIS_OCTAL; + break; + case 'b': + eflags |= VIS_NOSLASH; + break; + case 'F': + if ((foldwidth = atoi(optarg))<5) { + fprintf(stderr, + "vis: can't fold lines to less than 5 cols\n"); + exit(1); + } + /*FALLTHROUGH*/ + case 'f': + fold++; /* fold output lines to 80 cols */ + break; /* using hidden newline */ + case 'l': + markeol++; /* mark end of line with \$ */ + break; +#ifdef DEBUG + case 'd': + debug++; + break; +#endif + case '?': + default: + fprintf(stderr, + "usage: vis [-nwctsobf] [-F foldwidth]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + if (*argv) + while (*argv) { + if ((fp=fopen(*argv, "r")) != NULL) + process(fp, *argv); + else + fprintf(stderr, "vis: %s: %s\n", *argv, + (char *)strerror(errno)); + argv++; + } + else + process(stdin, ""); + exit(0); +} + +process(fp, filename) + FILE *fp; + char *filename; +{ + static int col = 0; + register char *cp = "\0"+1; /* so *(cp-1) starts out != '\n' */ + register int c, rachar; + register char nc; + char buff[5]; + + c = getc(fp); + while (c != EOF) { + rachar = getc(fp); + if (none) { + cp = buff; + *cp++ = c; + if (c == '\\') + *cp++ = '\\'; + *cp = '\0'; + } else if (markeol && c == '\n') { + cp = buff; + if ((eflags & VIS_NOSLASH) == 0) + *cp++ = '\\'; + *cp++ = '$'; + *cp++ = '\n'; + *cp = '\0'; + } else + (void) vis(buff, (char)c, eflags, (char)rachar); + + cp = buff; + if (fold) { +#ifdef DEBUG + if (debug) + printf("<%02d,", col); +#endif + col = foldit(cp, col, foldwidth); +#ifdef DEBUG + if (debug) + printf("%02d>", col); +#endif + } + do { + putchar(*cp); + } while (*++cp); + c = rachar; + } + /* + * terminate partial line with a hidden newline + */ + if (fold && *(cp-1) != '\n') + printf("\\\n"); +} diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile new file mode 100644 index 0000000..8e1a860 --- /dev/null +++ b/usr.bin/vmstat/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= vmstat +CFLAGS+=-I/sys +MAN8= vmstat.0 +BINGRP= kmem +BINMODE=2555 +DPADD= names.c ${LIBKVM} +LDADD= -lkvm + +.include diff --git a/usr.bin/vmstat/names.c b/usr.bin/vmstat/names.c new file mode 100644 index 0000000..ba16804 --- /dev/null +++ b/usr.bin/vmstat/names.c @@ -0,0 +1,242 @@ +/*- + * 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. + * + * @(#)names.c 8.1 (Berkeley) 6/6/93 + */ + +#if !defined(hp300) && !defined(tahoe) && !defined(vax) && \ + !defined(luna68k) && !defined(mips) +char *defdrives[] = { 0 }; +#endif + +#if defined(hp300) || defined(luna68k) +#if defined(hp300) +#include +#else +#include +#endif + +char *defdrives[] = { "sd0", "sd1", "sd2", "rd0", "rd1", "rd2", 0 }; + +int +read_names() +{ + register char *p; + register u_long hp; + static char buf[BUFSIZ]; + struct hp_device hdev; + struct driver hdrv; + char name[10]; + + hp = namelist[X_HPDINIT].n_value; + if (hp == 0) { + (void)fprintf(stderr, + "disk init info not in namelist\n"); + return (0); + } + p = buf; + for (;; hp += sizeof hdev) { + (void)kvm_read(kd, hp, &hdev, sizeof hdev); + if (hdev.hp_driver == 0) + break; + if (hdev.hp_dk < 0 || hdev.hp_alive == 0 || + hdev.hp_cdriver == 0) + continue; + (void)kvm_read(kd, (u_long)hdev.hp_driver, &hdrv, sizeof hdrv); + (void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name); + dr_name[hdev.hp_dk] = p; + p += sprintf(p, "%s%d", name, hdev.hp_unit) + 1; + } + return (1); +} +#endif /* hp300 || luna68k */ + +#ifdef tahoe +#include + +char *defdrives[] = { "dk0", "dk1", "dk2", 0 }; + +int +read_names() +{ + register char *p; + struct vba_device udev, *up; + struct vba_driver udrv; + char name[10]; + static char buf[BUFSIZ]; + + up = (struct vba_device *)namelist[X_VBDINIT].n_value; + if (up == 0) { + (void) fprintf(stderr, + "disk init info not in namelist\n"); + return (0); + } + p = buf; + for (;; up += sizeof udev) { + (void)kvm_read(kd, up, &udev, sizeof udev); + if (udev.ui_driver == 0) + break; + if (udev.ui_dk < 0 || udev.ui_alive == 0) + continue; + (void)kvm_read(kd, udev.ui_driver, &udrv, sizeof udrv); + (void)kvm_read(kd, udrv.ud_dname, name, sizeof name); + dr_name[udev.ui_dk] = p; + p += sprintf(p, "%s%d", name, udev.ui_unit); + } + return (1); +} +#endif /* tahoe */ + +#ifdef vax +#include +#include + +char *defdrives[] = { "hp0", "hp1", "hp2", 0 }; + +int +read_names() +{ + register char *p; + unsigned long mp, up; + struct mba_device mdev; + struct mba_driver mdrv; + struct uba_device udev; + struct uba_driver udrv; + char name[10]; + static char buf[BUFSIZ]; + + mp = namelist[X_MBDINIT].n_value; + up = namelist[X_UBDINIT].n_value; + if (mp == 0 && up == 0) { + (void)fprintf(stderr, + "disk init info not in namelist\n"); + return (0); + } + p = buf; + if (mp) + for (;; mp += sizeof mdev) { + (void)kvm_read(kd, mp, &mdev, sizeof mdev); + if (mdev.mi_driver == 0) + break; + if (mdev.mi_dk < 0 || mdev.mi_alive == 0) + continue; + (void)kvm_read(kd, mdev.mi_driver, &mdrv, sizeof mdrv); + (void)kvm_rea(kd, mdrv.md_dname, name, sizeof name); + dr_name[mdev.mi_dk] = p; + p += sprintf(p, "%s%d", name, mdev.mi_unit); + } + if (up) + for (;; up += sizeof udev) { + (void)kvm_read(kd, up, &udev, sizeof udev); + if (udev.ui_driver == 0) + break; + if (udev.ui_dk < 0 || udev.ui_alive == 0) + continue; + (void)kvm_read(kd, udev.ui_driver, &udrv, sizeof udrv); + (void)kvm_read(kd, udrv.ud_dname, name, sizeof name); + dr_name[udev.ui_dk] = p; + p += sprintf(p, "%s%d", name, udev.ui_unit); + } + return (1); +} +#endif /* vax */ + +#ifdef sun +#include + +int +read_names() +{ + static int once = 0; + struct mb_device mdev; + struct mb_driver mdrv; + short two_char; + char *cp = (char *) &two_char; + register struct mb_device *mp; + + mp = (struct mb_device *)namelist[X_MBDINIT].n_value; + if (mp == 0) { + (void)fprintf(stderr, + "disk init info not in namelist\n"); + return (0); + } + for (;; ++mp) { + (void)kvm_read(kd, mp++, &mdev, sizeof(mdev)); + if (mdev.md_driver == 0) + break; + if (mdev.md_dk < 0 || mdev.md_alive == 0) + continue; + (void)kvm_read(kd, mdev.md_driver, &mdrv, sizeof(mdrv)); + (void)kvm_read(kd, mdrv.mdr_dname, &two_char, sizeof(two_char)); + (void)sprintf(dr_name[mdev.md_dk], + "%c%c%d", cp[0], cp[1], mdev.md_unit); + } + return(1); +} +#endif /* sun */ + +#if defined(mips) +#include + +char *defdrives[] = { "rz0", "rz1", "rz2", "rz3", "rz4", "rz5", "rz6", 0 }; + +int +read_names() +{ + register char *p; + register u_long sp; + static char buf[BUFSIZ]; + struct scsi_device sdev; + struct driver hdrv; + char name[10]; + + sp = namelist[X_SCSI_DINIT].n_value; + if (sp == 0) { + (void)fprintf(stderr, "disk init info not in namelist\n"); + return (0); + } + p = buf; + for (;; sp += sizeof sdev) { + (void)kvm_read(kd, sp, &sdev, sizeof sdev); + if (sdev.sd_driver == 0) + break; + if (sdev.sd_dk < 0 || sdev.sd_alive == 0 || + sdev.sd_cdriver == 0) + continue; + (void)kvm_read(kd, (u_long)sdev.sd_driver, &hdrv, sizeof hdrv); + (void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name); + dr_name[sdev.sd_dk] = p; + p += sprintf(p, "%s%d", name, sdev.sd_unit) + 1; + } + return (1); +} +#endif /* mips */ diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 new file mode 100644 index 0000000..d2eb074 --- /dev/null +++ b/usr.bin/vmstat/vmstat.8 @@ -0,0 +1,206 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)vmstat.8 8.1 (Berkeley) 6/6/93 +.\" +.TH VMSTAT 1 "June 6, 1993" +.UC 4 +.SH NAME +vmstat \- report virtual memory statistics +.SH SYNOPSIS +.nf +.ft B +vmstat [ \-fimst ] [ \-c count ] [ \-M core ] [ \-N system ] +.ti +5 +[ \-w wait ] [ disks ] +.ft R +.fi +.SH DESCRIPTION +.I Vmstat +reports certain kernel statistics kept about process, virtual memory, +disk, trap and cpu activity. +.PP +The options are as follows: +.TP +\-c +Repeat the display +.I count +times. +The first display is for the time since a reboot and each subsequent report +is for the time period since the last display. +If no +.I wait +interval is specified, the default is 1 second. +.TP +\-f +Report on the number +.IR fork (2) +and +.IR vfork (2) +system calls since system startup, and the number of pages of virtual memory +involved in each. +.TP +\-i +Report on the number of interrupts taken by each device since system +startup. +.TP +\-M +Extract values associated with the name list from the specified core +instead of the default ``/dev/kmem''. +.TP +\-N +Extract the name list from the specified system instead of the default +``/vmunix''. +.TP +\-m +Report on the usage of kernel dynamic memory listed first by size of +allocation and then by type of usage. +.TP +\-s +Display the contents of the +.I sum +structure, giving the total number of several kinds of paging related +events which have occurred since system startup. +.TP +\-t +Report on the number of page in and page reclaims since system startup, +and the amount of time required by each. +.TP +\-w +Pause +.I wait +seconds between each display. +If no repeat +.I count +is specified, the default is infinity. +.PP +By default, +.I vmstat +displays the following information: +.PP +.TP +procs +Information about the numbers of processes in various states. +.sp +.RS +.nf +r in run queue +b blocked for resources (i/o, paging, etc.) +w runnable or short sleeper (< 20 secs) but swapped +.fi +.RE +.TP +memory +Information about the usage of virtual and real memory. +Virtual pages (reported in units of 1024 bytes) are considered active if +they belong to processes which are running or have run in the last 20 +seconds. +.sp +.RS +.nf +avm active virtual pages +fre size of the free list +.fi +.RE +.TP +page +Information about page faults and paging activity. +These are averaged each five seconds, and given in units per second. +.sp +.RS +.nf +re page reclaims (simulating reference bits) +at pages attached (found in free list) +pi pages paged in +po pages paged out +fr pages freed per second +de anticipated short term memory shortfall +sr pages scanned by clock algorithm, per-second +.fi +.RE +.TP +disks +Disk operations per second (this field is system dependent). +Typically paging will be split across the available drives. +The header of the field is the first character of the disk name and +the unit number. +If more than four disk drives are configured in the system, +.I vmstat +displays only the first four drives. +To force +.I vmstat +to display specific drives, their names may be supplied on the command line. +.TP +faults +Trap/interrupt rate averages per second over last 5 seconds. +.sp +.RS +.nf +in device interrupts per interval (including clock interrupts) +sy system calls per interval +cs cpu context switch rate (switches/interval) +.fi +.RE +.TP +cpu +Breakdown of percentage usage of CPU time. +.sp +.RS +.nf +us user time for normal and low priority processes +sy system time +id cpu idle +.fi +.RE +.SH EXAMPLES +The command ``vmstat -i 5'' will print what the system is doing every five +seconds; this is a good choice of printing interval since this is how often +some of the statistics are sampled in the system. +Others vary every second and running the output for a while will make it +apparent which are recomputed every second. +.SH FILES +.ta \w'/dev/kmem 'u +/vmunix 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 +The \-c and \-w options are only available with the default output. diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c new file mode 100644 index 0000000..0f3f4ce --- /dev/null +++ b/usr.bin/vmstat/vmstat.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 1980, 1986, 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 copyright[] = +"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NEWVM /* XXX till old has been updated or purged */ +struct nlist namelist[] = { +#define X_CPTIME 0 + { "_cp_time" }, +#define X_DK_NDRIVE 1 + { "_dk_ndrive" }, +#define X_SUM 2 + { "_cnt" }, +#define X_BOOTTIME 3 + { "_boottime" }, +#define X_DKXFER 4 + { "_dk_xfer" }, +#define X_HZ 5 + { "_hz" }, +#define X_STATHZ 6 + { "_stathz" }, +#define X_NCHSTATS 7 + { "_nchstats" }, +#define X_INTRNAMES 8 + { "_intrnames" }, +#define X_EINTRNAMES 9 + { "_eintrnames" }, +#define X_INTRCNT 10 + { "_intrcnt" }, +#define X_EINTRCNT 11 + { "_eintrcnt" }, +#define X_KMEMSTAT 12 + { "_kmemstats" }, +#define X_KMEMBUCKETS 13 + { "_bucket" }, +#ifdef notdef +#define X_DEFICIT 14 + { "_deficit" }, +#define X_FORKSTAT 15 + { "_forkstat" }, +#define X_REC 16 + { "_rectime" }, +#define X_PGIN 17 + { "_pgintime" }, +#define X_XSTATS 18 + { "_xstats" }, +#define X_END 18 +#else +#define X_END 14 +#endif +#if defined(hp300) || defined(luna68k) +#define X_HPDINIT (X_END) + { "_hp_dinit" }, +#endif +#ifdef mips +#define X_SCSI_DINIT (X_END) + { "_scsi_dinit" }, +#endif +#ifdef tahoe +#define X_VBDINIT (X_END) + { "_vbdinit" }, +#define X_CKEYSTATS (X_END+1) + { "_ckeystats" }, +#define X_DKEYSTATS (X_END+2) + { "_dkeystats" }, +#endif +#ifdef vax +#define X_MBDINIT (X_END) + { "_mbdinit" }, +#define X_UBDINIT (X_END+1) + { "_ubdinit" }, +#endif + { "" }, +}; + +struct _disk { + long time[CPUSTATES]; + long *xfer; +} cur, last; + +struct vmmeter sum, osum; +char **dr_name; +int *dr_select, dk_ndrive, ndrives; + +int winlines = 20; + +kvm_t *kd; + +#define FORKSTAT 0x01 +#define INTRSTAT 0x02 +#define MEMSTAT 0x04 +#define SUMSTAT 0x08 +#define TIMESTAT 0x10 +#define VMSTAT 0x20 + +#include "names.c" /* disk names -- machine dependent */ + +void cpustats(), dkstats(), dointr(), domem(), dosum(); +void dovmstat(), kread(), usage(); +#ifdef notdef +void dotimes(), doforkst(); +#endif + +main(argc, argv) + register int argc; + register char **argv; +{ + extern int optind; + extern char *optarg; + register int c, todo; + u_int interval; + int reps; + char *memf, *nlistf; + char errbuf[_POSIX2_LINE_MAX]; + + memf = nlistf = NULL; + interval = reps = todo = 0; + while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != EOF) { + switch (c) { + case 'c': + reps = atoi(optarg); + break; +#ifndef notdef + case 'f': + todo |= FORKSTAT; + break; +#endif + case 'i': + todo |= INTRSTAT; + break; + case 'M': + memf = optarg; + break; + case 'm': + todo |= MEMSTAT; + break; + case 'N': + nlistf = optarg; + break; + case 's': + todo |= SUMSTAT; + break; +#ifndef notdef + case 't': + todo |= TIMESTAT; + break; +#endif + case 'w': + interval = atoi(optarg); + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (todo == 0) + todo = VMSTAT; + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + if (kd == 0) { + (void)fprintf(stderr, + "vmstat: kvm_openfiles: %s\n", errbuf); + exit(1); + } + + if ((c = kvm_nlist(kd, namelist)) != 0) { + if (c > 0) { + (void)fprintf(stderr, + "vmstat: undefined symbols:"); + for (c = 0; + c < sizeof(namelist)/sizeof(namelist[0]); c++) + if (namelist[c].n_type == 0) + fprintf(stderr, " %s", + namelist[c].n_name); + (void)fputc('\n', stderr); + } else + (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n", + kvm_geterr(kd)); + exit(1); + } + + if (todo & VMSTAT) { + char **getdrivedata(); + struct winsize winsize; + + argv = getdrivedata(argv); + winsize.ws_row = 0; + (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); + if (winsize.ws_row > 0) + winlines = winsize.ws_row; + + } + +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + interval = atoi(*argv); + if (*++argv) + reps = atoi(*argv); + } +#endif + + if (interval) { + if (!reps) + reps = -1; + } else if (reps) + interval = 1; + +#ifdef notdef + if (todo & FORKSTAT) + doforkst(); +#endif + if (todo & MEMSTAT) + domem(); + if (todo & SUMSTAT) + dosum(); +#ifdef notdef + if (todo & TIMESTAT) + dotimes(); +#endif + if (todo & INTRSTAT) + dointr(); + if (todo & VMSTAT) + dovmstat(interval, reps); + exit(0); +} + +char ** +getdrivedata(argv) + char **argv; +{ + register int i; + register char **cp; + char buf[30]; + + kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive)); + if (dk_ndrive <= 0) { + (void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive); + exit(1); + } + dr_select = calloc((size_t)dk_ndrive, sizeof(int)); + dr_name = calloc((size_t)dk_ndrive, sizeof(char *)); + for (i = 0; i < dk_ndrive; i++) + dr_name[i] = NULL; + cur.xfer = calloc((size_t)dk_ndrive, sizeof(long)); + last.xfer = calloc((size_t)dk_ndrive, sizeof(long)); + if (!read_names()) + exit (1); + for (i = 0; i < dk_ndrive; i++) + if (dr_name[i] == NULL) { + (void)sprintf(buf, "??%d", i); + dr_name[i] = strdup(buf); + } + + /* + * Choose drives to be displayed. Priority goes to (in order) drives + * supplied as arguments, default drives. If everything isn't filled + * in and there are drives not taken care of, display the first few + * that fit. + */ +#define BACKWARD_COMPATIBILITY + for (ndrives = 0; *argv; ++argv) { +#ifdef BACKWARD_COMPATIBILITY + if (isdigit(**argv)) + break; +#endif + for (i = 0; i < dk_ndrive; i++) { + if (strcmp(dr_name[i], *argv)) + continue; + dr_select[i] = 1; + ++ndrives; + break; + } + } + for (i = 0; i < dk_ndrive && ndrives < 4; i++) { + if (dr_select[i]) + continue; + for (cp = defdrives; *cp; cp++) + if (strcmp(dr_name[i], *cp) == 0) { + dr_select[i] = 1; + ++ndrives; + break; + } + } + for (i = 0; i < dk_ndrive && ndrives < 4; i++) { + if (dr_select[i]) + continue; + dr_select[i] = 1; + ++ndrives; + } + return(argv); +} + +long +getuptime() +{ + static time_t now, boottime; + time_t uptime; + + if (boottime == 0) + kread(X_BOOTTIME, &boottime, sizeof(boottime)); + (void)time(&now); + uptime = now - boottime; + if (uptime <= 0 || uptime > 60*60*24*365*10) { + (void)fprintf(stderr, + "vmstat: time makes no sense; namelist must be wrong.\n"); + exit(1); + } + return(uptime); +} + +int hz, hdrcnt; + +void +dovmstat(interval, reps) + u_int interval; + int reps; +{ + struct vmtotal total; + time_t uptime, halfuptime; + void needhdr(); + int mib[2], size; + + uptime = getuptime(); + halfuptime = uptime / 2; + (void)signal(SIGCONT, needhdr); + + if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) + kread(X_STATHZ, &hz, sizeof(hz)); + if (!hz) + kread(X_HZ, &hz, sizeof(hz)); + + for (hdrcnt = 1;;) { + if (!--hdrcnt) + printhdr(); + kread(X_CPTIME, cur.time, sizeof(cur.time)); + kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive); + kread(X_SUM, &sum, sizeof(sum)); + size = sizeof(total); + mib[0] = CTL_VM; + mib[1] = VM_METER; + if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { + printf("Can't get kerninfo: %s\n", strerror(errno)); + bzero(&total, sizeof(total)); + } + (void)printf("%2d%2d%2d", + total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); +#define pgtok(a) ((a) * sum.v_page_size >> 10) +#define rate(x) (((x) + halfuptime) / uptime) /* round */ + (void)printf("%6ld%6ld ", + pgtok(total.t_avm), pgtok(total.t_free)); +#ifdef NEWVM + (void)printf("%4lu ", rate(sum.v_faults - osum.v_faults)); + (void)printf("%3lu ", + rate(sum.v_reactivated - osum.v_reactivated)); + (void)printf("%3lu ", rate(sum.v_pageins - osum.v_pageins)); + (void)printf("%3lu %3lu ", + rate(sum.v_pageouts - osum.v_pageouts), 0); +#else + (void)printf("%3lu %2lu ", + rate(sum.v_pgrec - (sum.v_xsfrec+sum.v_xifrec) - + (osum.v_pgrec - (osum.v_xsfrec+osum.v_xifrec))), + rate(sum.v_xsfrec + sum.v_xifrec - + osum.v_xsfrec - osum.v_xifrec)); + (void)printf("%3lu ", + rate(pgtok(sum.v_pgpgin - osum.v_pgpgin))); + (void)printf("%3lu %3lu ", + rate(pgtok(sum.v_pgpgout - osum.v_pgpgout)), + rate(pgtok(sum.v_dfree - osum.v_dfree))); + (void)printf("%3d ", pgtok(deficit)); +#endif + (void)printf("%3lu ", rate(sum.v_scan - osum.v_scan)); + dkstats(); + (void)printf("%4lu %4lu %3lu ", + rate(sum.v_intr - osum.v_intr), + rate(sum.v_syscall - osum.v_syscall), + rate(sum.v_swtch - osum.v_swtch)); + cpustats(); + (void)printf("\n"); + (void)fflush(stdout); + if (reps >= 0 && --reps <= 0) + break; + osum = sum; + uptime = interval; + /* + * We round upward to avoid losing low-frequency events + * (i.e., >= 1 per interval but < 1 per second). + */ + halfuptime = (uptime + 1) / 2; + (void)sleep(interval); + } +} + +printhdr() +{ + register int i; + + (void)printf(" procs memory page%*s", 20, ""); + if (ndrives > 1) + (void)printf("disks %*s faults cpu\n", + ndrives * 3 - 6, ""); + else + (void)printf("%*s faults cpu\n", ndrives * 3, ""); +#ifndef NEWVM + (void)printf(" r b w avm fre re at pi po fr de sr "); +#else + (void)printf(" r b w avm fre flt re pi po fr sr "); +#endif + for (i = 0; i < dk_ndrive; i++) + if (dr_select[i]) + (void)printf("%c%c ", dr_name[i][0], + dr_name[i][strlen(dr_name[i]) - 1]); + (void)printf(" in sy cs us sy id\n"); + hdrcnt = winlines - 2; +} + +/* + * Force a header to be prepended to the next output. + */ +void +needhdr() +{ + + hdrcnt = 1; +} + +#ifdef notdef +void +dotimes() +{ + u_int pgintime, rectime; + + kread(X_REC, &rectime, sizeof(rectime)); + kread(X_PGIN, &pgintime, sizeof(pgintime)); + kread(X_SUM, &sum, sizeof(sum)); + (void)printf("%u reclaims, %u total time (usec)\n", + sum.v_pgrec, rectime); + (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); + (void)printf("\n"); + (void)printf("%u page ins, %u total time (msec)\n", + sum.v_pgin, pgintime / 10); + (void)printf("average: %8.1f msec / page in\n", + pgintime / (sum.v_pgin * 10.0)); +} +#endif + +pct(top, bot) + long top, bot; +{ + long ans; + + if (bot == 0) + return(0); + ans = (quad_t)top * 100 / bot; + return (ans); +} + +#define PCT(top, bot) pct((long)(top), (long)(bot)) + +#if defined(tahoe) +#include +#endif + +void +dosum() +{ + struct nchstats nchstats; +#ifndef NEWVM + struct xstats xstats; +#endif + long nchtotal; +#if defined(tahoe) + struct keystats keystats; +#endif + + kread(X_SUM, &sum, sizeof(sum)); + (void)printf("%9u cpu context switches\n", sum.v_swtch); + (void)printf("%9u device interrupts\n", sum.v_intr); + (void)printf("%9u software interrupts\n", sum.v_soft); +#ifdef vax + (void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma); +#endif + (void)printf("%9u traps\n", sum.v_trap); + (void)printf("%9u system calls\n", sum.v_syscall); + (void)printf("%9u total faults taken\n", sum.v_faults); + (void)printf("%9u swap ins\n", sum.v_swpin); + (void)printf("%9u swap outs\n", sum.v_swpout); + (void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE); + (void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE); + (void)printf("%9u page ins\n", sum.v_pageins); + (void)printf("%9u page outs\n", sum.v_pageouts); + (void)printf("%9u pages paged in\n", sum.v_pgpgin); + (void)printf("%9u pages paged out\n", sum.v_pgpgout); + (void)printf("%9u pages reactivated\n", sum.v_reactivated); + (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); + (void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE); + (void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE); + (void)printf("%9u pages examined by the clock daemon\n", sum.v_scan); + (void)printf("%9u revolutions of the clock hand\n", sum.v_rev); +#ifdef NEWVM + (void)printf("%9u VM object cache lookups\n", sum.v_lookups); + (void)printf("%9u VM object hits\n", sum.v_hits); + (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); + (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); + (void)printf("%9u pages freed by daemon\n", sum.v_dfree); + (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); + (void)printf("%9u pages free\n", sum.v_free_count); + (void)printf("%9u pages wired down\n", sum.v_wire_count); + (void)printf("%9u pages active\n", sum.v_active_count); + (void)printf("%9u pages inactive\n", sum.v_inactive_count); + (void)printf("%9u bytes per page\n", sum.v_page_size); +#else + (void)printf("%9u sequential process pages freed\n", sum.v_seqfree); + (void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec, + PCT(sum.v_fastpgrec, sum.v_pgrec)); + (void)printf("%9u reclaims from free list\n", sum.v_pgfrec); + (void)printf("%9u executable fill pages created\n", + sum.v_nexfod / CLSIZE); + (void)printf("%9u executable fill page faults\n", + sum.v_exfod / CLSIZE); + (void)printf("%9u swap text pages found in free list\n", + sum.v_xsfrec); + (void)printf("%9u inode text pages found in free list\n", + sum.v_xifrec); + (void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE); + (void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE); + (void)printf("%9u pages freed by the clock daemon\n", + sum.v_dfree / CLSIZE); +#endif + kread(X_NCHSTATS, &nchstats, sizeof(nchstats)); + nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits + + nchstats.ncs_badhits + nchstats.ncs_falsehits + + nchstats.ncs_miss + nchstats.ncs_long; + (void)printf("%9ld total name lookups\n", nchtotal); + (void)printf( + "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", + "", PCT(nchstats.ncs_goodhits, nchtotal), + PCT(nchstats.ncs_neghits, nchtotal), + PCT(nchstats.ncs_pass2, nchtotal)); + (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", + PCT(nchstats.ncs_badhits, nchtotal), + PCT(nchstats.ncs_falsehits, nchtotal), + PCT(nchstats.ncs_long, nchtotal)); +#ifndef NEWVM + kread(X_XSTATS, &xstats, sizeof(xstats)); + (void)printf("%9lu total calls to xalloc (cache hits %d%%)\n", + xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc)); + (void)printf("%9s sticky %lu flushed %lu unused %lu\n", "", + xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused); + (void)printf("%9lu total calls to xfree", xstats.free); + (void)printf(" (sticky %lu cached %lu swapped %lu)\n", + xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap); +#endif +#if defined(tahoe) + kread(X_CKEYSTATS, &keystats, sizeof(keystats)); + (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", + keystats.ks_allocs, "code cache keys allocated", + PCT(keystats.ks_allocfree, keystats.ks_allocs), + PCT(keystats.ks_norefs, keystats.ks_allocs), + PCT(keystats.ks_taken, keystats.ks_allocs), + PCT(keystats.ks_shared, keystats.ks_allocs)); + kread(X_DKEYSTATS, &keystats, sizeof(keystats)); + (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", + keystats.ks_allocs, "data cache keys allocated", + PCT(keystats.ks_allocfree, keystats.ks_allocs), + PCT(keystats.ks_norefs, keystats.ks_allocs), + PCT(keystats.ks_taken, keystats.ks_allocs), + PCT(keystats.ks_shared, keystats.ks_allocs)); +#endif +} + +#ifdef notdef +void +doforkst() +{ + struct forkstat fks; + + kread(X_FORKSTAT, &fks, sizeof(struct forkstat)); + (void)printf("%d forks, %d pages, average %.2f\n", + fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork); + (void)printf("%d vforks, %d pages, average %.2f\n", + fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork); +} +#endif + +void +dkstats() +{ + register int dn, state; + double etime; + long tmp; + + for (dn = 0; dn < dk_ndrive; ++dn) { + tmp = cur.xfer[dn]; + cur.xfer[dn] -= last.xfer[dn]; + last.xfer[dn] = tmp; + } + etime = 0; + for (state = 0; state < CPUSTATES; ++state) { + tmp = cur.time[state]; + cur.time[state] -= last.time[state]; + last.time[state] = tmp; + etime += cur.time[state]; + } + if (etime == 0) + etime = 1; + etime /= hz; + for (dn = 0; dn < dk_ndrive; ++dn) { + if (!dr_select[dn]) + continue; + (void)printf("%2.0f ", cur.xfer[dn] / etime); + } +} + +void +cpustats() +{ + register int state; + double pct, total; + + total = 0; + for (state = 0; state < CPUSTATES; ++state) + total += cur.time[state]; + if (total) + pct = 100 / total; + else + pct = 0; + (void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct); + (void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct); + (void)printf("%2.0f", cur.time[CP_IDLE] * pct); +} + +void +dointr() +{ + register long *intrcnt, inttotal, uptime; + register int nintr, inamlen; + register char *intrname; + + uptime = getuptime(); + nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; + inamlen = + namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; + intrcnt = malloc((size_t)nintr); + intrname = malloc((size_t)inamlen); + if (intrcnt == NULL || intrname == NULL) { + (void)fprintf(stderr, "vmstat: %s.\n", strerror(errno)); + exit(1); + } + kread(X_INTRCNT, intrcnt, (size_t)nintr); + kread(X_INTRNAMES, intrname, (size_t)inamlen); + (void)printf("interrupt total rate\n"); + inttotal = 0; + nintr /= sizeof(long); + while (--nintr >= 0) { + if (*intrcnt) + (void)printf("%-12s %8ld %8ld\n", intrname, + *intrcnt, *intrcnt / uptime); + intrname += strlen(intrname) + 1; + inttotal += *intrcnt++; + } + (void)printf("Total %8ld %8ld\n", inttotal, inttotal / uptime); +} + +/* + * These names are defined in . + */ +char *kmemnames[] = INITKMEMNAMES; + +void +domem() +{ + register struct kmembuckets *kp; + register struct kmemstats *ks; + register int i, j; + int len, size, first; + long totuse = 0, totfree = 0, totreq = 0; + char *name; + struct kmemstats kmemstats[M_LAST]; + struct kmembuckets buckets[MINBUCKET + 16]; + + kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); + (void)printf("Memory statistics by bucket size\n"); + (void)printf( + " Size In Use Free Requests HighWater Couldfree\n"); + for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) { + if (kp->kb_calls == 0) + continue; + size = 1 << i; + (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size, + kp->kb_total - kp->kb_totalfree, + kp->kb_totalfree, kp->kb_calls, + kp->kb_highwat, kp->kb_couldfree); + totfree += size * kp->kb_totalfree; + } + + kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats)); + (void)printf("\nMemory usage type by bucket size\n"); + (void)printf(" Size Type(s)\n"); + kp = &buckets[MINBUCKET]; + for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) { + if (kp->kb_calls == 0) + continue; + first = 1; + len = 8; + for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { + if (ks->ks_calls == 0) + continue; + if ((ks->ks_size & j) == 0) + continue; + name = kmemnames[i] ? kmemnames[i] : "undefined"; + len += 2 + strlen(name); + if (first) + printf("%8d %s", j, name); + else + printf(","); + if (len >= 80) { + printf("\n\t "); + len = 10 + strlen(name); + } + if (!first) + printf(" %s", name); + first = 0; + } + printf("\n"); + } + + (void)printf( + "\nMemory statistics by type Type Kern\n"); + (void)printf( +" Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n"); + for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { + if (ks->ks_calls == 0) + continue; + (void)printf("%11s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u", + kmemnames[i] ? kmemnames[i] : "undefined", + ks->ks_inuse, (ks->ks_memuse + 1023) / 1024, + (ks->ks_maxused + 1023) / 1024, + (ks->ks_limit + 1023) / 1024, ks->ks_calls, + ks->ks_limblocks, ks->ks_mapblocks); + first = 1; + for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) { + if ((ks->ks_size & j) == 0) + continue; + if (first) + printf(" %d", j); + else + printf(",%d", j); + first = 0; + } + printf("\n"); + totuse += ks->ks_memuse; + totreq += ks->ks_calls; + } + (void)printf("\nMemory Totals: In Use Free Requests\n"); + (void)printf(" %7ldK %6ldK %8ld\n", + (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); +} + +/* + * kread reads something from the kernel, given its nlist index. + */ +void +kread(nlx, addr, size) + int nlx; + void *addr; + size_t size; +{ + char *sym; + + if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { + sym = namelist[nlx].n_name; + if (*sym == '_') + ++sym; + (void)fprintf(stderr, + "vmstat: symbol %s not defined\n", sym); + exit(1); + } + if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { + sym = namelist[nlx].n_name; + if (*sym == '_') + ++sym; + (void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd)); + exit(1); + } +} + +void +usage() +{ + (void)fprintf(stderr, +#ifndef NEWVM + "usage: vmstat [-fimst] [-c count] [-M core] \ +[-N system] [-w wait] [disks]\n"); +#else + "usage: vmstat [-ims] [-c count] [-M core] \ +[-N system] [-w wait] [disks]\n"); +#endif + exit(1); +} diff --git a/usr.bin/w/Makefile b/usr.bin/w/Makefile new file mode 100644 index 0000000..6217753 --- /dev/null +++ b/usr.bin/w/Makefile @@ -0,0 +1,14 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= w +SRCS= fmt.c pr_time.c proc_compare.c w.c +MAN1= w.0 uptime.0 +DPADD= ${LIBKVM} +LDADD= -lkvm +BINGRP= kmem +BINMODE=2555 +LINKS= ${BINDIR}/w ${BINDIR}/uptime + +.PATH: ${.CURDIR}/../../bin/ps + +.include diff --git a/usr.bin/w/extern.h b/usr.bin/w/extern.h new file mode 100644 index 0000000..1ee237c --- /dev/null +++ b/usr.bin/w/extern.h @@ -0,0 +1,39 @@ +/*- + * 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. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +struct proc; +void pr_attime __P((time_t *, time_t *)); +void pr_idle __P((time_t)); +int proc_compare __P((struct proc *, struct proc *)); diff --git a/usr.bin/w/pr_time.c b/usr.bin/w/pr_time.c new file mode 100644 index 0000000..87fffb3 --- /dev/null +++ b/usr.bin/w/pr_time.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 1990, 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[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include + +#include "extern.h" + +/* + * pr_attime -- + * Print the time since the user logged in. + * + * Note: SCCS forces the bizarre string manipulation, things like + * 8.2 get replaced in the source code. + */ +void +pr_attime(started, now) + time_t *started, *now; +{ + static char buf[256]; + struct tm *tp; + time_t diff; + char fmt[20]; + + tp = localtime(started); + diff = *now - *started; + + /* If more than a week, use day-month-year. */ + if (diff > SECSPERDAY * DAYSPERWEEK) + (void)strcpy(fmt, "%d%b%y"); + + /* If not today, use day-hour-am/pm. */ + else if (*now / SECSPERDAY != *started / SECSPERDAY) { + (void)strcpy(fmt, __CONCAT("%a%", "I%p")); + } + + /* Default is hh:mm{am,pm}. */ + else { + (void)strcpy(fmt, __CONCAT("%l:%", "M%p")); + } + + (void)strftime(buf, sizeof(buf), fmt, tp); + (void)printf("%s", buf); +} + +/* + * pr_idle -- + * Display the idle time. + */ +void +pr_idle(idle) + time_t idle; +{ + /* If idle more than 36 hours, print as a number of days. */ + if (idle >= 36 * SECSPERHOUR) + (void)printf(" %ddays ", idle / SECSPERDAY); + + /* If idle more than an hour, print as HH:MM. */ + else if (idle >= SECSPERHOUR) + (void)printf(" %2d:%02d ", + idle / SECSPERHOUR, (idle % SECSPERHOUR) / SECSPERMIN); + + /* Else print the minutes idle. */ + else + (void)printf(" %2d ", idle / SECSPERMIN); +} diff --git a/usr.bin/w/proc_compare.c b/usr.bin/w/proc_compare.c new file mode 100644 index 0000000..e95359c --- /dev/null +++ b/usr.bin/w/proc_compare.c @@ -0,0 +1,120 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)proc_compare.c 8.2 (Berkeley) 9/23/93"; +#endif /* not lint */ + +#include +#include +#include + +#include "extern.h" + +/* + * Returns 1 if p2 is "better" than p1 + * + * The algorithm for picking the "interesting" process is thus: + * + * 1) Only foreground processes are eligible - implied. + * 2) Runnable processes are favored over anything else. The runner + * with the highest cpu utilization is picked (p_estcpu). Ties are + * broken by picking the highest pid. + * 3) The sleeper with the shortest sleep time is next. With ties, + * we pick out just "short-term" sleepers (P_SINTR == 0). + * 4) Further ties are broken by picking the highest pid. + * + * If you change this, be sure to consider making the change in the kernel + * too (^T in kern/tty.c). + * + * TODO - consider whether pctcpu should be used. + */ + +#define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) +#define TESTAB(a, b) ((a)<<1 | (b)) +#define ONLYA 2 +#define ONLYB 1 +#define BOTH 3 + +int +proc_compare(p1, p2) + register struct proc *p1, *p2; +{ + + if (p1 == NULL) + return (1); + /* + * see if at least one of them is runnable + */ + switch (TESTAB(ISRUN(p1), ISRUN(p2))) { + case ONLYA: + return (0); + case ONLYB: + return (1); + case BOTH: + /* + * tie - favor one with highest recent cpu utilization + */ + if (p2->p_estcpu > p1->p_estcpu) + return (1); + if (p1->p_estcpu > p2->p_estcpu) + return (0); + return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ + } + /* + * weed out zombies + */ + switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { + case ONLYA: + return (1); + case ONLYB: + return (0); + case BOTH: + return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ + } + /* + * pick the one with the smallest sleep time + */ + if (p2->p_slptime > p1->p_slptime) + return (0); + if (p1->p_slptime > p2->p_slptime) + return (1); + /* + * favor one sleeping in a non-interruptible sleep + */ + if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0) + return (1); + if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0) + return (0); + return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ +} diff --git a/usr.bin/w/uptime.1 b/usr.bin/w/uptime.1 new file mode 100644 index 0000000..a5eb169 --- /dev/null +++ b/usr.bin/w/uptime.1 @@ -0,0 +1,60 @@ +.\" Copyright (c) 1980, 1990, 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. +.\" +.\" @(#)uptime.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt UPTIME 1 +.Os BSD 3 +.Sh NAME +.Nm uptime +.Nd show how long system has been running +.Sh SYNOPSIS +.Nm uptime +.Sh DESCRIPTION +The +.Nm uptime +utility displays the current time, +the length of time the system has been up, +the number of users, and the load average of the system over the last +1, 5, and 15 minutes. +.Sh FILES +.Bl -tag -width /vmunix +.It Pa /vmunix +system name list +.El +.Sh SEE ALSO +.Xr w 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/w/w.1 b/usr.bin/w/w.1 new file mode 100644 index 0000000..4e4f5d3 --- /dev/null +++ b/usr.bin/w/w.1 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)w.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt W 1 +.Os BSD 4 +.Sh NAME +.Nm w +.Nd "who present users are and what they are doing" +.Sh SYNOPSIS +.Nm w +.Op Fl hin +.Op Fl M Ar core +.Op Fl N Ar system +.Op Ar user +.Sh DESCRIPTION +The +.Nm w +utility prints a summary of the current activity on the system, +including what each user is doing. +The first line displays the current time of day, how long the system has +been running, the number of users logged into the system, and the load +averages. +The load average numbers give the number of jobs in the run queue averaged +over 1, 5 and 15 minutes. +.Pp +The fields output are the user's login name, the name of the terminal the +user is on, the host from which the user is logged in, the time the user +logged on, the time since the user last typed anything, +and the name and arguments of the current process. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl h +Suppress the heading. +.It Fl i +Output is sorted by idle time. +.It Fl M +Extract values associated with the name list from the specified +core instead of the default +.Dq /dev/kmem . +.It Fl N +Extract the name list from the specified system instead of the +default +.Dq /vmunix . +.It Fl n +Show network addresses as numbers (normally +.Nm w +interprets addresses and attempts to display them symbolically). +.El +.Pp +If a +.Ar user +name is specified, the output is restricted to that user. +.Sh FILES +.Bl -tag -width /var/run/utmp -compact +.It Pa /var/run/utmp +list of users on the system +.El +.Sh SEE ALSO +.Xr who 1 , +.Xr finger 1 , +.Xr ps 1 , +.Xr uptime 1 , +.Sh BUGS +The notion of the +.Dq current process +is muddy. +The current algorithm is ``the highest numbered process on the terminal +that is not ignoring interrupts, or, if there is none, the highest numbered +process on the terminal''. +This fails, for example, in critical sections of programs like the shell +and editor, or when faulty programs running in the background fork and fail +to ignore interrupts. +(In cases where no process can be found, +.Nm w +prints +.Dq \- . ) +.Pp +The +.Tn CPU +time is only an estimate, in particular, if someone leaves a background +process running after logging out, the person currently on that terminal is +.Dq charged +with the time. +.Pp +Background processes are not shown, even though they account for +much of the load on the system. +.Pp +Sometimes processes, typically those in the background, are printed with +null or garbaged arguments. +In these cases, the name of the command is printed in parentheses. +.Pp +The +.Nm w +utility does not know about the new conventions for detection of background +jobs. +It will sometimes find a background job instead of the right one. +.Sh COMPATIBILITY +The +.Fl f , +.Fl l , +.Fl s , +and +.Fl w +flags are no longer supported. +.Sh HISTORY +The +.Nm +command appeared in +.Ux 3.0 . diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c new file mode 100644 index 0000000..1a7b526 --- /dev/null +++ b/usr.bin/w/w.c @@ -0,0 +1,426 @@ +/*- + * Copyright (c) 1980, 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 copyright[] = +"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94"; +#endif /* not lint */ + +/* + * w - print system status (who and what) + * + * This program is similar to the systat command on Tenex/Tops 10/20 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" + +struct timeval boottime; +struct utmp utmp; +struct winsize ws; +kvm_t *kd; +time_t now; /* the current time of day */ +time_t uptime; /* time of last reboot & elapsed time since */ +int ttywidth; /* width of tty */ +int argwidth; /* width of tty */ +int header = 1; /* true if -h flag: don't print heading */ +int nflag; /* true if -n flag: don't convert addrs */ +int sortidle; /* sort bu idle time */ +char *sel_user; /* login of particular user selected */ +char domain[MAXHOSTNAMELEN]; + +/* + * One of these per active utmp entry. + */ +struct entry { + struct entry *next; + struct utmp utmp; + dev_t tdev; /* dev_t of terminal */ + time_t idle; /* idle time of terminal in seconds */ + struct kinfo_proc *kp; /* `most interesting' proc */ + char *args; /* arg list of interesting process */ +} *ep, *ehead = NULL, **nextp = &ehead; + +static void pr_header __P((time_t *, int)); +static struct stat + *ttystat __P((char *)); +static void usage __P((int)); + +char *fmt_argv __P((char **, char *, int)); /* ../../bin/ps/fmt.c */ + +int +main(argc, argv) + int argc; + char **argv; +{ + extern char *__progname; + struct kinfo_proc *kp; + struct hostent *hp; + struct stat *stp; + FILE *ut; + u_long l; + size_t arglen; + int ch, i, nentries, nusers, wcmd; + char *memf, *nlistf, *p, *vis_args, *x; + char buf[MAXHOSTNAMELEN], errbuf[256]; + + /* Are we w(1) or uptime(1)? */ + p = __progname; + if (*p == '-') + p++; + if (*p == 'u') { + wcmd = 0; + p = ""; + } else { + wcmd = 1; + p = "hiflM:N:nsuw"; + } + + memf = nlistf = NULL; + while ((ch = getopt(argc, argv, p)) != EOF) + switch (ch) { + case 'h': + header = 0; + break; + case 'i': + sortidle = 1; + break; + case 'M': + header = 0; + memf = optarg; + break; + case 'N': + nlistf = optarg; + break; + case 'n': + nflag = 1; + break; + case 'f': case 'l': case 's': case 'u': case 'w': + warnx("[-flsuw] no longer supported"); + /* FALLTHROUGH */ + case '?': + default: + usage(wcmd); + } + argc -= optind; + argv += optind; + + if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL) + errx(1, "%s", errbuf); + + (void)time(&now); + if ((ut = fopen(_PATH_UTMP, "r")) == NULL) + err(1, "%s", _PATH_UTMP); + + if (*argv) + sel_user = *argv; + + for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) { + if (utmp.ut_name[0] == '\0') + continue; + ++nusers; + if (wcmd == 0 || (sel_user && + strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0)) + continue; + if ((ep = calloc(1, sizeof(struct entry))) == NULL) + err(1, NULL); + *nextp = ep; + nextp = &(ep->next); + memmove(&(ep->utmp), &utmp, sizeof(struct utmp)); + stp = ttystat(ep->utmp.ut_line); + ep->tdev = stp->st_rdev; +#ifdef CPU_CONSDEV + /* + * If this is the console device, attempt to ascertain + * the true console device dev_t. + */ + if (ep->tdev == 0) { + int mib[2]; + size_t size; + + mib[0] = CTL_MACHDEP; + mib[1] = CPU_CONSDEV; + size = sizeof(dev_t); + (void) sysctl(mib, 2, &ep->tdev, &size, NULL, 0); + } +#endif + if ((ep->idle = now - stp->st_atime) < 0) + ep->idle = 0; + } + (void)fclose(ut); + + if (header || wcmd == 0) { + pr_header(&now, nusers); + if (wcmd == 0) + exit (0); + } + +#define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n" +#define WUSED (sizeof (HEADER) - sizeof ("WHAT\n")) + (void)printf(HEADER); + + if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL) + err(1, "%s", kvm_geterr(kd)); + for (i = 0; i < nentries; i++, kp++) { + struct proc *p = &kp->kp_proc; + struct eproc *e; + + if (p->p_stat == SIDL || p->p_stat == SZOMB) + continue; + e = &kp->kp_eproc; + for (ep = ehead; ep != NULL; ep = ep->next) { + if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) { + /* + * Proc is in foreground of this terminal + */ + if (proc_compare(&ep->kp->kp_proc, p)) + ep->kp = kp; + break; + } + } + } + if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 && + ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 && + ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0) + ttywidth = 79; + else + ttywidth = ws.ws_col - 1; + argwidth = ttywidth - WUSED; + if (argwidth < 4) + argwidth = 8; + for (ep = ehead; ep != NULL; ep = ep->next) { + if (ep->kp == NULL) { + ep->args = "-"; + continue; + } + ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth), + ep->kp->kp_proc.p_comm, MAXCOMLEN); + if (ep->args == NULL) + err(1, NULL); + } + /* sort by idle time */ + if (sortidle && ehead != NULL) { + struct entry *from = ehead, *save; + + ehead = NULL; + while (from != NULL) { + for (nextp = &ehead; + (*nextp) && from->idle >= (*nextp)->idle; + nextp = &(*nextp)->next) + continue; + save = from; + from = from->next; + save->next = *nextp; + *nextp = save; + } + } + + if (!nflag) + if (gethostname(domain, sizeof(domain) - 1) < 0 || + (p = strchr(domain, '.')) == 0) + domain[0] = '\0'; + else { + domain[sizeof(domain) - 1] = '\0'; + memmove(domain, p, strlen(p) + 1); + } + + if ((vis_args = malloc(argwidth * 4 + 1)) == NULL) + err(1, NULL); + for (ep = ehead; ep != NULL; ep = ep->next) { + p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-"; + if ((x = strchr(p, ':')) != NULL) + *x++ = '\0'; + if (!nflag && isdigit(*p) && + (long)(l = inet_addr(p)) != -1 && + (hp = gethostbyaddr((char *)&l, sizeof(l), AF_INET))) { + if (domain[0] != '\0') { + p = hp->h_name; + p += strlen(hp->h_name); + p -= strlen(domain); + if (p > hp->h_name && strcmp(p, domain) == 0) + *p = '\0'; + } + p = hp->h_name; + } + if (x) { + (void)snprintf(buf, sizeof(buf), "%s:%s", p, x); + p = buf; + } + (void)printf("%-*.*s %-2.2s %-*.*s ", + UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name, + strncmp(ep->utmp.ut_line, "tty", 3) ? + ep->utmp.ut_line : ep->utmp.ut_line + 3, + UT_HOSTSIZE, UT_HOSTSIZE, *p ? p : "-"); + pr_attime(&ep->utmp.ut_time, &now); + pr_idle(ep->idle); + if (ep->args != NULL) { + arglen = strlen(ep->args); + strvisx(vis_args, ep->args, + arglen > argwidth ? argwidth : arglen, + VIS_TAB | VIS_NL | VIS_NOSLASH); + } + (void)printf("%.*s\n", argwidth, ep->args); + } + exit(0); +} + +static void +pr_header(nowp, nusers) + time_t *nowp; + int nusers; +{ + double avenrun[3]; + time_t uptime; + int days, hrs, i, mins; + int mib[2]; + size_t size; + char buf[256]; + + /* + * Print time of day. + * + * SCCS forces the string manipulation below, as it replaces + * %, M, and % in a character string with the file name. + */ + (void)strftime(buf, sizeof(buf), + __CONCAT("%l:%","M%p"), localtime(nowp)); + (void)printf("%s ", buf); + + /* + * Print how long system has been up. + * (Found by looking getting "boottime" from the kernel) + */ + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + size = sizeof(boottime); + if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && + boottime.tv_sec != 0) { + uptime = now - boottime.tv_sec; + uptime += 30; + days = uptime / SECSPERDAY; + uptime %= SECSPERDAY; + hrs = uptime / SECSPERHOUR; + uptime %= SECSPERHOUR; + mins = uptime / SECSPERMIN; + (void)printf(" up"); + if (days > 0) + (void)printf(" %d day%s,", days, days > 1 ? "s" : ""); + if (hrs > 0 && mins > 0) + (void)printf(" %2d:%02d,", hrs, mins); + else { + if (hrs > 0) + (void)printf(" %d hr%s,", + hrs, hrs > 1 ? "s" : ""); + if (mins > 0) + (void)printf(" %d min%s,", + mins, mins > 1 ? "s" : ""); + } + } + + /* Print number of users logged in to system */ + (void)printf(" %d user%s", nusers, nusers > 1 ? "s" : ""); + + /* + * Print 1, 5, and 15 minute load averages. + */ + if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1) + (void)printf(", no load average information available\n"); + else { + (void)printf(", load averages:"); + for (i = 0; i < (sizeof(avenrun) / sizeof(avenrun[0])); i++) { + if (i > 0) + (void)printf(","); + (void)printf(" %.2f", avenrun[i]); + } + (void)printf("\n"); + } +} + +static struct stat * +ttystat(line) + char *line; +{ + static struct stat sb; + char ttybuf[MAXPATHLEN]; + + (void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", _PATH_DEV, line); + if (stat(ttybuf, &sb)) + err(1, "%s", ttybuf); + return (&sb); +} + +static void +usage(wcmd) + int wcmd; +{ + if (wcmd) + (void)fprintf(stderr, + "usage: w: [-hin] [-M core] [-N system] [user]\n"); + else + (void)fprintf(stderr, "uptime\n"); + exit (1); +} diff --git a/usr.bin/wall/Makefile b/usr.bin/wall/Makefile new file mode 100644 index 0000000..65abb61 --- /dev/null +++ b/usr.bin/wall/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= wall +SRCS= ttymsg.c wall.c +BINGRP= tty +BINMODE=2555 + +.include diff --git a/usr.bin/wall/ttymsg.c b/usr.bin/wall/ttymsg.c new file mode 100644 index 0000000..6a7c3d1 --- /dev/null +++ b/usr.bin/wall/ttymsg.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1989, 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[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Display the contents of a uio structure on a terminal. Used by wall(1), + * syslogd(8), and talkd(8). Forks and finishes in child if write would block, + * waiting up to tmout seconds. Returns pointer to error string on unexpected + * error; string is not newline-terminated. Various "normal" errors are + * ignored (exclusive-use, lack of permission, etc.). + */ +char * +ttymsg(iov, iovcnt, line, tmout) + struct iovec *iov; + int iovcnt; + char *line; + int tmout; +{ + static char device[MAXNAMLEN] = _PATH_DEV; + static char errbuf[1024]; + register int cnt, fd, left, wret; + struct iovec localiov[6]; + int forked = 0; + + if (iovcnt > sizeof(localiov) / sizeof(localiov[0])) + return ("too many iov's (change code in wall/ttymsg.c)"); + + (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); + if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) { + /* A slash is an attempt to break security... */ + (void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"", + device); + return (errbuf); + } + + /* + * open will fail on slip lines or exclusive-use lines + * if not running as root; not an error. + */ + if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { + if (errno == EBUSY || errno == EACCES) + return (NULL); + (void) snprintf(errbuf, sizeof(errbuf), + "%s: %s", device, strerror(errno)); + return (errbuf); + } + + for (cnt = left = 0; cnt < iovcnt; ++cnt) + left += iov[cnt].iov_len; + + for (;;) { + wret = writev(fd, iov, iovcnt); + if (wret >= left) + break; + if (wret >= 0) { + left -= wret; + if (iov != localiov) { + bcopy(iov, localiov, + iovcnt * sizeof(struct iovec)); + iov = localiov; + } + for (cnt = 0; wret >= iov->iov_len; ++cnt) { + wret -= iov->iov_len; + ++iov; + --iovcnt; + } + if (wret) { + iov->iov_base += wret; + iov->iov_len -= wret; + } + continue; + } + if (errno == EWOULDBLOCK) { + int cpid, off = 0; + + if (forked) { + (void) close(fd); + _exit(1); + } + cpid = fork(); + if (cpid < 0) { + (void) snprintf(errbuf, sizeof(errbuf), + "fork: %s", strerror(errno)); + (void) close(fd); + return (errbuf); + } + if (cpid) { /* parent */ + (void) close(fd); + return (NULL); + } + forked++; + /* wait at most tmout seconds */ + (void) signal(SIGALRM, SIG_DFL); + (void) signal(SIGTERM, SIG_DFL); /* XXX */ + (void) sigsetmask(0); + (void) alarm((u_int)tmout); + (void) fcntl(fd, O_NONBLOCK, &off); + continue; + } + /* + * We get ENODEV on a slip line if we're running as root, + * and EIO if the line just went away. + */ + if (errno == ENODEV || errno == EIO) + break; + (void) close(fd); + if (forked) + _exit(1); + (void) snprintf(errbuf, sizeof(errbuf), + "%s: %s", device, strerror(errno)); + return (errbuf); + } + + (void) close(fd); + if (forked) + _exit(0); + return (NULL); +} diff --git a/usr.bin/wall/wall.1 b/usr.bin/wall/wall.1 new file mode 100644 index 0000000..ed2f4c9 --- /dev/null +++ b/usr.bin/wall/wall.1 @@ -0,0 +1,63 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)wall.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt WALL 1 +.Os BSD 4 +.Sh NAME +.Nm wall +.Nd write a message to users +.Sh SYNOPSIS +.Nm wall +.Op Ar file +.Sh DESCRIPTION +.Nm Wall +displays the contents of +.Ar file +or, by default, its standard input, on the terminals of all +currently logged in users. +.Pp +Only the super-user can write on the +terminals of users who have chosen +to deny messages or are using a program which +automatically denies messages. +.Sh SEE ALSO +.Xr mesg 1 , +.Xr talk 1 , +.Xr write 1 , +.Xr shutdown 8 +.Sh HISTORY +A +.Nm +command appeared in +.At v7 . diff --git a/usr.bin/wall/wall.c b/usr.bin/wall/wall.c new file mode 100644 index 0000000..9b120ed --- /dev/null +++ b/usr.bin/wall/wall.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1988, 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1988, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; +#endif /* not lint */ + +/* + * This program is not related to David Wall, whose Stanford Ph.D. thesis + * is entitled "Mechanisms for Broadcast and Selective Broadcast". + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +void makemsg __P((char *)); + +#define IGNOREUSER "sleeper" + +int nobanner; +int mbufsize; +char *mbuf; + +/* ARGSUSED */ +int +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + int ch; + struct iovec iov; + struct utmp utmp; + FILE *fp; + char *p, *ttymsg(); + char line[sizeof(utmp.ut_line) + 1]; + + while ((ch = getopt(argc, argv, "n")) != EOF) + switch (ch) { + case 'n': + /* undoc option for shutdown: suppress banner */ + if (geteuid() == 0) + nobanner = 1; + break; + case '?': + default: +usage: + (void)fprintf(stderr, "usage: wall [file]\n"); + exit(1); + } + argc -= optind; + argv += optind; + if (argc > 1) + goto usage; + + makemsg(*argv); + + if (!(fp = fopen(_PATH_UTMP, "r"))) { + (void)fprintf(stderr, "wall: cannot read %s.\n", _PATH_UTMP); + exit(1); + } + iov.iov_base = mbuf; + iov.iov_len = mbufsize; + /* NOSTRICT */ + while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) { + if (!utmp.ut_name[0] || + !strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) + continue; + strncpy(line, utmp.ut_line, sizeof(utmp.ut_line)); + line[sizeof(utmp.ut_line)] = '\0'; + if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) + (void)fprintf(stderr, "wall: %s\n", p); + } + exit(0); +} + +void +makemsg(fname) + char *fname; +{ + register int ch, cnt; + struct tm *lt; + struct passwd *pw; + struct stat sbuf; + time_t now, time(); + FILE *fp; + int fd; + char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15]; + char *getlogin(), *strcpy(), *ttyname(); + + (void)strcpy(tmpname, _PATH_TMP); + (void)strcat(tmpname, "/wall.XXXXXX"); + if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) { + (void)fprintf(stderr, "wall: can't open temporary file.\n"); + exit(1); + } + (void)unlink(tmpname); + + if (!nobanner) { + if (!(whom = getlogin())) + whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; + (void)gethostname(hostname, sizeof(hostname)); + (void)time(&now); + lt = localtime(&now); + + /* + * all this stuff is to blank out a square for the message; + * we wrap message lines at column 79, not 80, because some + * terminals wrap after 79, some do not, and we can't tell. + * Which means that we may leave a non-blank character + * in column 80, but that can't be helped. + */ + (void)fprintf(fp, "\r%79s\r\n", " "); + (void)sprintf(lbuf, "Broadcast Message from %s@%s", + whom, hostname); + (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); + (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2), + lt->tm_hour, lt->tm_min); + (void)fprintf(fp, "%-79.79s\r\n", lbuf); + } + (void)fprintf(fp, "%79s\r\n", " "); + + if (fname && !(freopen(fname, "r", stdin))) { + (void)fprintf(stderr, "wall: can't read %s.\n", fname); + exit(1); + } + while (fgets(lbuf, sizeof(lbuf), stdin)) + for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { + if (cnt == 79 || ch == '\n') { + for (; cnt < 79; ++cnt) + putc(' ', fp); + putc('\r', fp); + putc('\n', fp); + cnt = 0; + } else + putc(ch, fp); + } + (void)fprintf(fp, "%79s\r\n", " "); + rewind(fp); + + if (fstat(fd, &sbuf)) { + (void)fprintf(stderr, "wall: can't stat temporary file.\n"); + exit(1); + } + mbufsize = sbuf.st_size; + if (!(mbuf = malloc((u_int)mbufsize))) { + (void)fprintf(stderr, "wall: out of memory.\n"); + exit(1); + } + if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) { + (void)fprintf(stderr, "wall: can't read temporary file.\n"); + exit(1); + } + (void)close(fd); +} diff --git a/usr.bin/wc/Makefile b/usr.bin/wc/Makefile new file mode 100644 index 0000000..07da67a --- /dev/null +++ b/usr.bin/wc/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= wc + +.include diff --git a/usr.bin/wc/wc.1 b/usr.bin/wc/wc.1 new file mode 100644 index 0000000..64c047b --- /dev/null +++ b/usr.bin/wc/wc.1 @@ -0,0 +1,109 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, 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. +.\" +.\" @(#)wc.1 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt WC 1 +.Os +.Sh NAME +.Nm wc +.Nd word, line, and byte count +.Sh SYNOPSIS +.Nm wc +.Op Fl clw +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm wc +utility displays the number of lines, words, and bytes contained in each +input +.Ar file +(or standard input, by default) to the standard output. +A line is defined as a string of characters delimited by a +character, +and a word is defined as a string of characters delimited by white space +characters. +White space characters are the set of characters for which the +.Xr isspace 3 +function returns true. +If more than one input file is specified, a line of cumulative counts +for all the files is displayed on a separate line after the output for +the last file. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl c +The number of bytes in each input file +is written to the standard output. +.It Fl l +The number of lines in each input file +is written to the standard output. +.It Fl w +The number of words in each input file +is written to the standard output. +.El +.Pp +When an option is specified, +.Nm wc +only reports the information requested by that option. +The default action is equivalent to specifying all of the flags. +.Pp +If no files are specified, the standard input is used and no +file name is displayed. +.Pp +The +.Nm wc +utility exits 0 on success, and >0 if an error occurs. +.Sh SEE ALSO +.Xr isspace 3 +.Sh COMPATIBILITY +Historically, the +.Nm wc +utility was documented to define a word as a ``maximal string of +characters delimited by , or characters''. +The implementation, however, didn't handle non-printing characters +correctly so that `` ^D^E '' counted as 6 spaces, while ``foo^D^Ebar'' +counted as 8 characters. +4BSD systems after 4.3BSD modified the implementation to be consistent +with the documentation. +This implementation defines a ``word'' in terms of the +.Xr isspace 3 +function, as required by +.St -p1003.2 . +.Sh STANDARDS +The +.Nm wc +function conforms to +.St -p1003.2 . diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c new file mode 100644 index 0000000..a50196c --- /dev/null +++ b/usr.bin/wc/wc.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1980, 1987, 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 copyright[] = +"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +u_long tlinect, twordct, tcharct; +int doline, doword, dochar; + +void cnt __P((char *)); +void err __P((const char *, ...)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int ch; + int total; + + while ((ch = getopt(argc, argv, "lwc")) != EOF) + switch((char)ch) { + case 'l': + doline = 1; + break; + case 'w': + doword = 1; + break; + case 'c': + dochar = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + /* Wc's flags are on by default. */ + if (doline + doword + dochar == 0) + doline = doword = dochar = 1; + + total = 0; + if (!*argv) { + cnt(NULL); + (void)printf("\n"); + } + else do { + cnt(*argv); + (void)printf(" %s\n", *argv); + ++total; + } while(*++argv); + + if (total > 1) { + if (doline) + (void)printf(" %7ld", tlinect); + if (doword) + (void)printf(" %7ld", twordct); + if (dochar) + (void)printf(" %7ld", tcharct); + (void)printf(" total\n"); + } + exit(0); +} + +void +cnt(file) + char *file; +{ + register u_char *p; + register short gotsp; + register int ch, len; + register u_long linect, wordct, charct; + struct stat sb; + int fd; + u_char buf[MAXBSIZE]; + + fd = STDIN_FILENO; + linect = wordct = charct = 0; + if (file) { + if ((fd = open(file, O_RDONLY, 0)) < 0) + err("%s: %s", file, strerror(errno)); + if (doword) + goto word; + /* + * Line counting is split out because it's a lot faster to get + * lines than to get words, since the word count requires some + * logic. + */ + if (doline) { + while (len = read(fd, buf, MAXBSIZE)) { + if (len == -1) + err("%s: %s", file, strerror(errno)); + charct += len; + for (p = buf; len--; ++p) + if (*p == '\n') + ++linect; + } + tlinect += linect; + (void)printf(" %7lu", linect); + if (dochar) { + tcharct += charct; + (void)printf(" %7lu", charct); + } + (void)close(fd); + return; + } + /* + * If all we need is the number of characters and it's a + * regular or linked file, just stat the puppy. + */ + if (dochar) { + if (fstat(fd, &sb)) + err("%s: %s", file, strerror(errno)); + if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { + (void)printf(" %7qu", sb.st_size); + tcharct += sb.st_size; + (void)close(fd); + return; + } + } + } + + /* Do it the hard way... */ +word: for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) { + if (len == -1) + err("%s: %s", file, strerror(errno)); + /* + * This loses in the presence of multi-byte characters. + * To do it right would require a function to return a + * character while knowing how many bytes it consumed. + */ + charct += len; + for (p = buf; len--;) { + ch = *p++; + if (ch == '\n') + ++linect; + if (isspace(ch)) + gotsp = 1; + else if (gotsp) { + gotsp = 0; + ++wordct; + } + } + } + if (doline) { + tlinect += linect; + (void)printf(" %7lu", linect); + } + if (doword) { + twordct += wordct; + (void)printf(" %7lu", wordct); + } + if (dochar) { + tcharct += charct; + (void)printf(" %7lu", charct); + } + (void)close(fd); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: wc [-clw] [files]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "wc: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/what/Makefile b/usr.bin/what/Makefile new file mode 100644 index 0000000..41a3f42 --- /dev/null +++ b/usr.bin/what/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= what + +.include diff --git a/usr.bin/what/what.1 b/usr.bin/what/what.1 new file mode 100644 index 0000000..e3556cc --- /dev/null +++ b/usr.bin/what/what.1 @@ -0,0 +1,68 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)what.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt WHAT 1 +.Os BSD 4 +.Sh NAME +.Nm what +.Nd "show what versions of object modules were used to construct a file" +.Sh SYNOPSIS +.Nm what +.Ar name Ar ... +.Sh DESCRIPTION +.Nm What +reads each file +.Ar name +and searches for sequences of the form +.Dq \&@(#) +as inserted by the source code control system. It prints the remainder +of the string following this marker, up to a null character, newline, double +quote, or +.Dq \&> character. +.Sh BUGS +As +.Bx +is not licensed to distribute +.Tn SCCS +this is a rewrite of the +.Nm what +command which is part of +.Tn SCCS , +and may not behave exactly the same as that +command does. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/what/what.c b/usr.bin/what/what.c new file mode 100644 index 0000000..769f6d5 --- /dev/null +++ b/usr.bin/what/what.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1980, 1988, 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 copyright[] = +"@(#) Copyright (c) 1980, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)what.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include + +/* + * what + */ +/* ARGSUSED */ +main(argc, argv) + int argc; + char **argv; +{ + if (!*++argv) + search(); + else do { + if (!freopen(*argv, "r", stdin)) { + perror(*argv); + exit(1); + } + printf("%s\n", *argv); + search(); + } while(*++argv); + exit(0); +} + +search() +{ + register int c; + + while ((c = getchar()) != EOF) { +loop: if (c != '@') + continue; + if ((c = getchar()) != '(') + goto loop; + if ((c = getchar()) != '#') + goto loop; + if ((c = getchar()) != ')') + goto loop; + putchar('\t'); + while ((c = getchar()) != EOF && c && c != '"' && + c != '>' && c != '\n') + putchar(c); + putchar('\n'); + } +} diff --git a/usr.bin/whatis/Makefile b/usr.bin/whatis/Makefile new file mode 100644 index 0000000..8655a7c --- /dev/null +++ b/usr.bin/whatis/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= whatis +SRCS= whatis.c config.c +.PATH: ${.CURDIR}/../man + +.include diff --git a/usr.bin/whatis/whatis.1 b/usr.bin/whatis/whatis.1 new file mode 100644 index 0000000..0f1b0a1 --- /dev/null +++ b/usr.bin/whatis/whatis.1 @@ -0,0 +1,105 @@ +.\" Copyright (c) 1989, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)whatis.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt WHATIS 1 +.Os BSD 4 +.Sh NAME +.Nm whatis +.Nd describe what a command is +.Sh SYNOPSIS +.Nm whatis +.Op Fl M Ar path +.Op Fl m Ar path +.Ar command Ar ... +.Sh DESCRIPTION +.Nm Whatis +looks up a given command and gives the header line from the manual page. +You can then use the +.Xr man 1 +command to get more information. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl M Ar path +Override the list of standard directories +.Nm whatis +searches for its database named +.Dq Pa whatis.db . +The supplied +.Ar path +must be a colon +.Dq \&: +separated list of directories. +This search path may also be set using the environment variable +.Ev MANPATH . +.It Fl m Ar path +Augment the list of standard directories +.Nm whatis +searches for its database named +.Dq Pa whatis.db . +The supplied +.Ar path +must be a colon +.Dq \&: +separated list of directories. +These directories will be searched before the standard directories +or the directories supplied with the +.Fl M +option or the +.Ev MANPATH +environment variable are searched. +.El +.Sh ENVIRONMENT +.Bl -tag -width MANPATH +.It Ev MANPATH +The standard search path used by +.Xr man 1 +may be overridden by specifying a path in the +.Ev MANPATH +environment variable. +.El +.Sh FILES +.Bl -tag -width whatis.db +.It Pa whatis.db +name of the whatis database +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr whereis 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/whatis/whatis.c b/usr.bin/whatis/whatis.c new file mode 100644 index 0000000..904f0e4 --- /dev/null +++ b/usr.bin/whatis/whatis.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)whatis.c 8.5 (Berkeley) 1/2/94"; +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "../man/config.h" +#include "../man/pathnames.h" + +#define MAXLINELEN 256 /* max line handled */ + +static int *found, foundman; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + ENTRY *ep; + TAG *tp; + int ch, rv; + char *beg, *conffile, **p, *p_augment, *p_path; + + conffile = NULL; + p_augment = p_path = NULL; + while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF) + switch (ch) { + case 'C': + conffile = optarg; + break; + case 'M': + case 'P': /* backward compatible */ + p_path = optarg; + break; + case 'm': + p_augment = optarg; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + if (argc < 1) + usage(); + + if ((found = malloc((u_int)argc * sizeof(int))) == NULL) + err(1, NULL); + memset(found, 0, argc * sizeof(int)); + + for (p = argv; *p; ++p) /* trim full paths */ + if (beg = rindex(*p, '/')) + *p = beg + 1; + + if (p_augment) + whatis(argv, p_augment, 1); + if (p_path || (p_path = getenv("MANPATH"))) + whatis(argv, p_path, 1); + else { + config(conffile); + ep = (tp = getlist("_whatdb")) == NULL ? + NULL : tp->list.tqh_first; + for (; ep != NULL; ep = ep->q.tqe_next) + whatis(argv, ep->s, 0); + } + + if (!foundman) { + fprintf(stderr, "whatis: no %s file found.\n", _PATH_WHATIS); + exit(1); + } + rv = 1; + for (p = argv; *p; ++p) + if (found[p - argv]) + rv = 0; + else + printf("%s: not found\n", *p); + exit(rv); +} + +whatis(argv, path, buildpath) + char **argv, *path; + int buildpath; +{ + register char *end, *name, **p; + char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1]; + + for (name = path; name; name = end) { /* through name list */ + if (end = index(name, ':')) + *end++ = '\0'; + + if (buildpath) { + char hold[MAXPATHLEN + 1]; + + (void)sprintf(hold, "%s/%s", name, _PATH_WHATIS); + name = hold; + } + + if (!freopen(name, "r", stdin)) + continue; + + foundman = 1; + + /* for each file found */ + while (fgets(buf, sizeof(buf), stdin)) { + dashtrunc(buf, wbuf); + for (p = argv; *p; ++p) + if (match(wbuf, *p)) { + printf("%s", buf); + found[p - argv] = 1; + + /* only print line once */ + while (*++p) + if (match(wbuf, *p)) + found[p - argv] = 1; + break; + } + } + } +} + +/* + * match -- + * match a full word + */ +match(bp, str) + register char *bp, *str; +{ + register int len; + register char *start; + + if (!*str || !*bp) + return(0); + for (len = strlen(str);;) { + for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp); + if (!*bp) + break; + for (start = bp++; + *bp && (*bp == '_' || isdigit(*bp) || isalpha(*bp)); ++bp); + if (bp - start == len && !strncasecmp(start, str, len)) + return(1); + } + return(0); +} + +/* + * dashtrunc -- + * truncate a string at " - " + */ +dashtrunc(from, to) + register char *from, *to; +{ + register int ch; + + for (; (ch = *from) && ch != '\n' && + (ch != ' ' || from[1] != '-' || from[2] != ' '); ++from) + *to++ = ch; + *to = '\0'; +} + +/* + * usage -- + * print usage message and die + */ +usage() +{ + (void)fprintf(stderr, + "usage: whatis [-C file] [-M path] [-m path] command ...\n"); + exit(1); +} diff --git a/usr.bin/whereis/Makefile b/usr.bin/whereis/Makefile new file mode 100644 index 0000000..87bc659 --- /dev/null +++ b/usr.bin/whereis/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= whereis + +.include diff --git a/usr.bin/who/Makefile b/usr.bin/who/Makefile new file mode 100644 index 0000000..8695ca2 --- /dev/null +++ b/usr.bin/who/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= who + +.include diff --git a/usr.bin/who/who.1 b/usr.bin/who/who.1 new file mode 100644 index 0000000..f8ac307 --- /dev/null +++ b/usr.bin/who/who.1 @@ -0,0 +1,105 @@ +.\" Copyright (c) 1986, 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. +.\" +.\" @(#)who.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt WHO 1 +.Os +.Sh NAME +.Nm who +.Nd display who is logged in +.Sh SYNOPSIS +.Nm who +.Op Ar am I +.Op Ar file +.Sh DESCRIPTION +The utility +.Nm who +displays +a list of all users currently logged on, showing for each user +the login name, +tty name, the date and time of login, and hostname if not local. +.Pp +Available options: +.Pp +.Bl -tag -width file +.It Ar \&am I +Returns the invoker's real user name. +.It Ar file +By default, +.Nm who +gathers information from the file +.Pa /var/run/utmp . +An alternate +.Ar file +may be specified which is usually +.Pa /var/run/wtmp +(or +.Pa /var/run/wtmp.[0-6] +depending on site policy as +.Pa wtmp +can grow quite large and daily versions may or may not +be kept around after compression by +.Xr ac 8 ) . +The +.Pa wtmp +file contains a record of every login, logout, +crash, shutdown and date change +since +.Pa wtmp +was last truncated or +created. +.El +.Pp +If +.Pa /var/log/wtmp +is being used as the file, the user name may be empty +or one of the special characters '|', '}' and '~'. Logouts produce +an output line without any user name. For more information on the +special characters, see +.Xr utmp 5 . +.Sh FILES +.Bl -tag -width /var/log/wtmp.[0-6] -compact +.It Pa /var/run/utmp +.It Pa /var/log/wtmp +.It Pa /var/log/wtmp.[0-6] +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr users 1 , +.Xr getuid 2 , +.Xr utmp 5 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/who/who.c b/usr.bin/who/who.c new file mode 100644 index 0000000..d1e6eb9 --- /dev/null +++ b/usr.bin/who/who.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +main(argc, argv) + int argc; + char **argv; +{ + register char *p; + struct utmp usr; + struct passwd *pw; + FILE *ufp, *file(); + char *t, *rindex(), *strcpy(), *strncpy(), *ttyname(); + time_t time(); + + switch (argc) { + case 1: /* who */ + ufp = file(_PATH_UTMP); + /* only entries with both name and line fields */ + while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) + if (*usr.ut_name && *usr.ut_line) + output(&usr); + break; + case 2: /* who utmp_file */ + ufp = file(argv[1]); + /* all entries */ + while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) + output(&usr); + break; + case 3: /* who am i */ + ufp = file(_PATH_UTMP); + + /* search through the utmp and find an entry for this tty */ + if (p = ttyname(0)) { + /* strip any directory component */ + if (t = rindex(p, '/')) + p = t + 1; + while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) + if (usr.ut_name && !strcmp(usr.ut_line, p)) { + output(&usr); + exit(0); + } + /* well, at least we know what the tty is */ + (void)strncpy(usr.ut_line, p, UT_LINESIZE); + } else + (void)strcpy(usr.ut_line, "tty??"); + pw = getpwuid(getuid()); + (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE); + (void)time(&usr.ut_time); + *usr.ut_host = '\0'; + output(&usr); + break; + default: + (void)fprintf(stderr, "usage: who [ file ]\n who am i\n"); + exit(1); + } + exit(0); +} + +output(up) + struct utmp *up; +{ + char *ctime(); + + (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, UT_NAMESIZE, up->ut_name, + UT_LINESIZE, UT_LINESIZE, up->ut_line); + (void)printf("%.12s", ctime(&up->ut_time) + 4); + if (*up->ut_host) + printf("\t(%.*s)", UT_HOSTSIZE, up->ut_host); + (void)putchar('\n'); +} + +FILE * +file(name) + char *name; +{ + extern int errno; + FILE *ufp; + char *strerror(); + + if (!(ufp = fopen(name, "r"))) { + (void)fprintf(stderr, "who: %s: %s.\n", name, strerror(errno)); + exit(1); + } + return(ufp); +} diff --git a/usr.bin/whois/Makefile b/usr.bin/whois/Makefile new file mode 100644 index 0000000..e6ab08f --- /dev/null +++ b/usr.bin/whois/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= whois + +.include diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1 new file mode 100644 index 0000000..dd9d81a --- /dev/null +++ b/usr.bin/whois/whois.1 @@ -0,0 +1,80 @@ +.\" Copyright (c) 1985, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)whois.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt WHOIS 1 +.Os BSD 4.3 +.Sh NAME +.Nm whois +.Nd Internet user name directory service +.Sh SYNOPSIS +.Nm whois +.Op Fl h Ar hostname +.Ar name ... +.Sh DESCRIPTION +.Nm Whois +looks up records in the Network Information Center +.Pq Tn NIC +database. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl h +Use the specified host instead of the default NIC (nic.ddn.mil). +.El +.Pp +The operands specified to +.Nm whois +are concatenated together (separated by white-space) and presented to +the +.Nm whois +server. +.Pp +The default action, unless directed otherwise with a special +.Ar name , +is to do a very broad search, looking for matches to +.Ar name +in all types of records and most fields (name, nicknames, hostname, net +address, etc.) in the database. +For more information as to what +.Ar name +operands have special meaning, and how to guide the search, use +the special name +.Dq Ar help . +.Sh SEE ALSO +RFC 812: Nicname/Whois +.Sh HISTORY +The +.Nm whois +command appeared in +.Bx 4.3 . diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c new file mode 100644 index 0000000..77d6c50 --- /dev/null +++ b/usr.bin/whois/whois.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#define NICHOST "whois.internic.net" + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + register FILE *sfi, *sfo; + register int ch; + struct sockaddr_in sin; + struct hostent *hp; + struct servent *sp; + int s; + char *host; + + host = NICHOST; + while ((ch = getopt(argc, argv, "h:")) != EOF) + switch((char)ch) { + case 'h': + host = optarg; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (!argc) + usage(); + + hp = gethostbyname(host); + if (hp == NULL) { + (void)fprintf(stderr, "whois: %s: ", host); + herror((char *)NULL); + exit(1); + } + host = hp->h_name; + s = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (s < 0) { + perror("whois: socket"); + exit(1); + } + bzero((caddr_t)&sin, sizeof (sin)); + sin.sin_family = hp->h_addrtype; + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + perror("whois: bind"); + exit(1); + } + bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); + sp = getservbyname("whois", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, "whois: whois/tcp: unknown service\n"); + exit(1); + } + sin.sin_port = sp->s_port; + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + perror("whois: connect"); + exit(1); + } + sfi = fdopen(s, "r"); + sfo = fdopen(s, "w"); + if (sfi == NULL || sfo == NULL) { + perror("whois: fdopen"); + (void)close(s); + exit(1); + } + while (argc-- > 1) + (void)fprintf(sfo, "%s ", *argv++); + (void)fprintf(sfo, "%s\r\n", *argv); + (void)fflush(sfo); + while ((ch = getc(sfi)) != EOF) + putchar(ch); + exit(0); +} + +usage() +{ + (void)fprintf(stderr, "usage: whois [-h hostname] name ...\n"); + exit(1); +} diff --git a/usr.bin/window/:tt b/usr.bin/window/:tt new file mode 100644 index 0000000..7ec4352 --- /dev/null +++ b/usr.bin/window/:tt @@ -0,0 +1,11 @@ +./"init"16t"end"n2p ++/"move"16t"insline"16t"delline"16t"delchar"n4p ++/"write"16t"putc"16tn2p ++/"clreol"16t"clreos"16t"clear"n3p ++/"scroll_down"16t"scroll_up"16t"setscroll"n3p ++/"setinsert"16t"setmodes"n2p ++/"modes"8t"nmodes"8t"insert"8t"ninsert"n4b ++/"row"16t"col"16t"scrtop"16t"sclbot"n4D ++/"nrow"16t"ncol"16t"hasins"8t"avlmods"8t"wrap"8t"retain"n2D4b ++/"frame" +*./16b diff --git a/usr.bin/window/:tty b/usr.bin/window/:tty new file mode 100644 index 0000000..2eb61ef --- /dev/null +++ b/usr.bin/window/:tty @@ -0,0 +1,6 @@ +./"sgttyb:"8t"ispeed"8t"ospeed"8t"erase"8t"kill"8t"flags"n8tbbC8tC8tx ++/"tchars:"8t"intrc"8t"quitc"8t"startc"8t"stopc"8t"eofc"8t"brkc" ++/8tC8tC8tC8tC8tC8tC ++/"ltchars:suspc"8t"dsuspc"8t"rprntc"8t"flushc"8t"werasc"8t"lnextc" ++/8tC8tC8tC8tC8tC8tC2+ ++/"lmode"16t"ldisc"16t"fflags"nXDX diff --git a/usr.bin/window/:var b/usr.bin/window/:var new file mode 100644 index 0000000..ff3de6b --- /dev/null +++ b/usr.bin/window/:var @@ -0,0 +1,2 @@ +./"left"16t"right"16t"v_type"8t"v_val"npp4+b3+x +*(.+8)/"name: "S diff --git a/usr.bin/window/:ww b/usr.bin/window/:ww new file mode 100644 index 0000000..0e99f0a --- /dev/null +++ b/usr.bin/window/:ww @@ -0,0 +1,19 @@ +./"state"8t"oflags"nbb++ ++/"forw"16t"back"16t"index"8t"order"nppbb++ ++/"w.nr"16t"w.nc"nDD ++/"w.t"16t"w.b"16t"w.l"16t"w.r"nDDDD ++/"b.nr"16t"b.nc"nDD ++/"b.t"16t"b.b"16t"b.l"16t"b.r"nDDDD ++/"i.nr"16t"i.nc"nDD ++/"i.t"16t"i.b"16t"i.l"16t"i.r"nDDDD ++/"cur.r"16t"cur.c"nDD ++/"win"16t"buf"16t"fmap"16t"nvis"npppp ++/"wstate"8t"modes"8t"insert"8t"mapnl"8t"noupd"n5b ++/"unctrl"8t"nointr"8t"hascurs"8t"hasframe"n4b ++/"ispty"8t"stopped"8t"pty"16t"socket"16t"pid"nbb+3D ++/"ttyname"n11C+ ++/"ob"16t"obe"16t"obp"16t"obq"n4p ++/"center"8t"id"8t"label"nbb++p ++/"alt.nr"16t"alt.nc"nDD ++/"alt.t"16t"alt.b"16t"alt.l"16t"alt.r"nDDDD ++/t diff --git a/usr.bin/window/Makefile b/usr.bin/window/Makefile new file mode 100644 index 0000000..53ab6da --- /dev/null +++ b/usr.bin/window/Makefile @@ -0,0 +1,22 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= window +CFLAGS+=-R -DVMIN_BUG +SRCS= char.c cmd.c cmd1.c cmd2.c cmd3.c cmd4.c cmd5.c cmd6.c cmd7.c \ + context.c error.c lcmd.c lcmd1.c lcmd2.c main.c mloop.c parser1.c \ + parser2.c parser3.c parser4.c parser5.c scanner.c startup.c string.c \ + ttf100.c ttgeneric.c tth19.c tth29.c ttinit.c ttoutput.c tttermcap.c \ + tttvi925.c ttwyse60.c ttwyse75.c ttzapple.c ttzentec.c var.c win.c \ + wwadd.c wwalloc.c wwbox.c wwchild.c wwclose.c wwclreol.c wwclreos.c \ + wwcursor.c wwdata.c wwdelchar.c wwdelete.c wwdelline.c wwdump.c \ + wwend.c wwenviron.c wwerror.c wwflush.c wwframe.c wwgets.c wwinit.c \ + wwinschar.c wwinsline.c wwiomux.c wwlabel.c wwmisc.c wwmove.c \ + wwopen.c wwprintf.c wwpty.c wwputc.c wwputs.c wwredraw.c \ + wwredrawwin.c wwrint.c wwscroll.c wwsize.c wwspawn.c wwsuspend.c \ + wwterminfo.c wwtty.c wwunframe.c wwupdate.c wwwrite.c xx.c xxflush.c \ + compress.c +MAN= window.0 +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap + +.include diff --git a/usr.bin/window/README b/usr.bin/window/README new file mode 100644 index 0000000..42d45b3 --- /dev/null +++ b/usr.bin/window/README @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)README 8.1 (Berkeley) 6/6/93 + */ + +Compilation notes: + + Compiler options: + + BYTE_ORDER (used only in ww.h) + It should already be defined in machine/endian.h. + The code knows about BIG_ENDIAN, LITTLE_ENDIAN, and PDP_ENDIAN. + It only cares about byte order in words, so PDP_ENDIAN + is the same as LITTLE_ENDIAN. + OLD_TTY + If you don't have Posix termios, then define this. + VMIN_BUG + Even if you have Posix termios, define this if the MIN and TIME + feature in noncanonical mode doesn't work correctly. + + Ok, there's another one, STR_DEBUG. It turns on consistency checks + in the string allocator. It's been left on since performace doesn't + seem to suffer. There's an abort() somewhere when an inconsistency + is found. It hasn't happened in years. + + The file local.h contains locally tunable constants. + + The makefile used to be updated with mkmf; it has been changed +at various times to use cpp -M and, currently, mkdep. The only library +it needs is termcap. + + Window, as is, only runs on 4.3 (or later) machines. + + On 4.2 machines, at least these modifications must be done: + + delete uses of window size ioctls: TIOCGWINSZ, TIOCSWINSZ, + struct winsize + add to ww.h + typedef int fd_set; + #define FD_ZERO(s) (*(s) = 0) + #define FD_SET(b, s) (*(s) |= 1 << (b)) + #define FD_ISSET(b, s) (*(s) & 1 << (b)) + add to ww.h + #define sigmask(s) (1 << (s) - 1) + + +A few notes about the internals: + + The window package. Windows are opened by calling wwopen(). +Wwwrite() is the primitive for writing to windows. Wwputc(), wwputs(), +and wwprintf() are also supported. Some of the outputs to windows are +delayed. Wwupdate() updates the terminal to match the internal screen +buffer. Wwspawn() spawns a child process on the other end of a window, +with its environment tailored to the window. Visible windows are +doubly linked in the order of their overlap. Wwadd() inserts a window +into the list at a given place. Wwdelete() deletes it. Windows not in +the list are not visible, though wwwrite() still works. Window was +written before the days of X and Sunview, so some of the terminology +is not standard. + + Most functions return -1 on error. Wwopen() returns the null +pointer. An error number is saved in wwerrno. Wwerror() returns an +error string based on wwerrno suitable for printing. + + The terminal drivers perform all output to the physical terminal, +including special functions like character and line insertion and +deletion. The window package keeps a list of known terminals. At +initialization time, the terminal type is matched against the list to +find the right terminal driver to use. The last driver, the generic +driver, matches all terminals and uses the termcap database. The +interface between the window package the terminal driver is the `tt' +structure. It contains pointers to functions to perform special +functions and terminal output, as well as flags about the +characteristics of the terminal. Most of these ideas are borrowed +from the Maryland window package, which in turn is based on Goslin's +Emacs. + + The IO system is semi-synchronous. Terminal input is signal +driven, and everything else is done synchronously with a single +select(). It is roughly event-driven, though not in a clean way. + + Normally, in both conversation mode and command mode, window +sleeps in a select() in wwiomux() waiting for data from the +pseudo-terminals. At the same time, terminal input causes SIGIO which +is caught by wwrint(). The select() returns when at least one of the +pseudo-terminals becomes ready for reading. + + Wwrint() is the interrupt handler for tty input. It reads input +into a linear buffer accessed through four pointers: + + +-------+--------------+----------------+ + | empty | data | empty | + +-------+--------------+----------------+ + ^ ^ ^ ^ + | | | | + wwib wwibp wwibq wwibe + +Wwrint() appends characters at the end and increments wwibq (*wwibq++ += c), and characters are taken off the buffer at wwibp using the +wwgetc() and wwpeekc() macros. As is the convention in C, wwibq +and wwibe point to one position beyond the end. In addition, +wwrint() will do a longjmp(wwjmpbuf) if wwsetjmp is true. This is +used by wwiomux() to interrupt the select() which would otherwise +resume after the interrupt. (Actually, I hear this is not true, +but the longjmp feature is used to avoid a race condition as well. +Anyway, it means I didn't have to depend on a feature in a +daily-changing kernel, but that's another story.) The macro +wwinterrupt() returns true if the input buffer is non-empty. +Wwupdate(), wwwrite(), and wwiomux() check this condition and will +return at the first convenient opportunity when it becomes true. +In the case of wwwrite(), the flag ww_nointr in the window structure +overrides this. This feature allows the user to interrupt lengthy +outputs safely. The structure of the input buffer is designed to +avoid race conditions without blocking interrupts. + + Actually, wwsetjmp and wwinterrupt() are part of a software +interrupt scheme used by the two interrupt catchers wwrint() and +wwchild(). Asserting the interrupt lets the synchronous parts of +the program know that there's an interesting asynchronous condition +(i.e., got a keyboard character, or a child process died) that they +might want to process before anything else. The synchronous routines +can check for this condition with wwinterrupt() or by arranging +that a longjmp() be done. + + Wwiomux() copies pseudo-terminal output into their corresponding +windows. Without anything to do, it blocks in a select(), waiting for +read ready on pseudo-terminals. Reads are done into per-window buffers +in the window structures. When there is at least one buffer non-empty, +wwiomux() finds the top most of these windows and writes it using +wwwrite(). Then the process is repeated. A non-blocking select() is +done after a wwwrite() to pick up any output that may have come in +during the write, which may take a long time. Specifically, we use +this to stop output or flush buffer when a pseudo-terminal tells us to +(we use pty packet mode). The select() blocks only when all of the +windows' buffers are empty. A wwupdate() is done prior to this, which +is the only time the screen is guaranteed to be completely up to date. +Wwiomux() loops until wwinterrupt() becomes true. + + The top level routine for all this is mloop(). In conversation +mode, it simply calls wwiomux(), which only returns when input is +available. The input buffer is then written to the pseudo-terminal of +the current window. If the escape character is found in the input, +command mode is entered. Otherwise, the process is repeated. In +command mode, control is transferred to docmd() which returns only when +conversation mode is reentered. Docmd() and other command processing +routines typically wait for input in a loop: + + while (wwpeekc() < 0) + wwiomux(); + +When the loop terminates, wwgetc() is used to read the input buffer. + + Output to the physical terminal is handled by the lowest level +routines of the window package, in the files ttoutput.c and tt.h. The +standard IO package is not used, to get better control over buffering +and to use non-blocking reads in wwrint(). The buffer size is set to +approximately one second of output time, based on the baudrate. + + The result of all this complexity is faster response time, +especially in output stopping and flushing. Wwwrite() checks +wwinterrupt() after every line. It also calls wwupdate() for each line +it writes. The output buffer is limited to one second of output time. +Thus, there is usually only a delay of one to two lines plus one second +after a ^C or ^S. Also, commands that produce lengthy output can be +aborted without actually showing all of it on the terminal. (Try the +'?' command followed by escape immediately.) diff --git a/usr.bin/window/alias.h b/usr.bin/window/alias.h new file mode 100644 index 0000000..ea63b49 --- /dev/null +++ b/usr.bin/window/alias.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)alias.h 8.1 (Berkeley) 6/6/93 + */ + +#define alias var +#define a_name r_name +#define a_buf r_val.v_str +#define a_flags r_val.v_type + + /* a_flags bits, must not interfere with v_type values */ +#define A_INUSE 0x010 /* already inuse */ + +#define alias_set(n, s) var_setstr1(&alias_head, n, s) +#define alias_walk(f, a) var_walk1(alias_head, f, a) +#define alias_unset(n) var_unset1(&alias_head, n) +#define alias_lookup(n) (*var_lookup1(&alias_head, n)) + +struct var *alias_head; diff --git a/usr.bin/window/char.c b/usr.bin/window/char.c new file mode 100644 index 0000000..34bea59 --- /dev/null +++ b/usr.bin/window/char.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)char.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "char.h" + +char _cmap[] = { + _C|_U, _C|_U, _C|_U, _C|_U, /* ^@ - ^C */ + _C|_U, _C|_U, _C|_U, _C|_U, /* ^D - ^G */ + _C, _C|_P, _C, _C|_U, /* ^H - ^K */ + _C|_U, _C, _C|_U, _C|_U, /* ^L - ^O */ + _C|_U, _C|_U, _C|_U, _C|_U, /* ^P - ^S */ + _C|_U, _C|_U, _C|_U, _C|_U, /* ^T - ^W */ + _C|_U, _C|_U, _C|_U, _C|_U, /* ^U - ^[ */ + _C|_U, _C|_U, _C|_U, _C|_U, /* ^\ - ^_ */ + + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _P|_U, + _P|_U, _P|_U, _P|_U, _C|_U, + + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U, + _C|_U, _C|_U, _C|_U, _C|_U +}; + +char *_unctrl[] = { + "^@", "^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", "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", "W", + "X", "Y", "Z", "[", "\\", "]", "^", "_", + "`", "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", "{", "|", "}", "~", "^?", + "\\200","\\201","\\202","\\203","\\204","\\205","\\206","\\207", + "\\210","\\211","\\212","\\213","\\214","\\215","\\216","\\217", + "\\220","\\221","\\222","\\223","\\224","\\225","\\226","\\227", + "\\230","\\231","\\232","\\233","\\234","\\235","\\236","\\237", + "\\240","\\241","\\242","\\243","\\244","\\245","\\246","\\247", + "\\250","\\251","\\252","\\253","\\254","\\255","\\256","\\257", + "\\260","\\261","\\262","\\263","\\264","\\265","\\266","\\267", + "\\270","\\271","\\272","\\273","\\274","\\275","\\276","\\277", + "\\300","\\301","\\302","\\303","\\304","\\305","\\306","\\307", + "\\310","\\311","\\312","\\313","\\314","\\315","\\316","\\317", + "\\320","\\321","\\322","\\323","\\324","\\325","\\326","\\327", + "\\330","\\331","\\332","\\333","\\334","\\335","\\336","\\337", + "\\340","\\341","\\342","\\343","\\344","\\345","\\346","\\347", + "\\350","\\351","\\352","\\353","\\354","\\355","\\356","\\357", + "\\360","\\361","\\362","\\363","\\364","\\365","\\366","\\367", + "\\370","\\371","\\372","\\373","\\374","\\375","\\376","\\377" +}; diff --git a/usr.bin/window/char.h b/usr.bin/window/char.h new file mode 100644 index 0000000..eb4774f --- /dev/null +++ b/usr.bin/window/char.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)char.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Macros and things to deal with control characters. + * + * Unctrl() is just like the standard function, except we don't want + * to include curses. + * Isctrl() returns true for all characters less than space and + * greater than or equal to delete. + * Isprt() is tab and all characters not isctrl(). It's used + * by wwwrite(). + * Isunctrl() includes all characters that should be expanded + * using unctrl() by wwwrite() if ww_unctrl is set. + */ + +extern char *_unctrl[]; +extern char _cmap[]; +#define ctrl(c) (c & 0x1f) +#define unctrl(c) (_unctrl[(unsigned char) (c)]) +#define _C 0x01 +#define _P 0x02 +#define _U 0x04 +#define isctrl(c) (_cmap[(unsigned char) (c)] & _C) +#define isprt(c) (_cmap[(unsigned char) (c)] & _P) +#define isunctrl(c) (_cmap[(unsigned char) (c)] & _U) diff --git a/usr.bin/window/cmd.c b/usr.bin/window/cmd.c new file mode 100644 index 0000000..cd105ea --- /dev/null +++ b/usr.bin/window/cmd.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "char.h" + +docmd() +{ + register char c; + register struct ww *w; + char out = 0; + + while (!out && !quit) { + if ((c = wwgetc()) < 0) { + if (terse) + wwsetcursor(0, 0); + else { + wwputs("Command: ", cmdwin); + wwcurtowin(cmdwin); + } + do + wwiomux(); + while ((c = wwgetc()) < 0); + } + if (!terse) + wwputc('\n', cmdwin); + switch (c) { + default: + if (c != escapec) + break; + case 'h': case 'j': case 'k': case 'l': + case 'y': case 'p': + case ctrl('y'): + case ctrl('e'): + case ctrl('u'): + case ctrl('d'): + case ctrl('b'): + case ctrl('f'): + case ctrl('s'): + case ctrl('q'): + case ctrl('['): + if (selwin == 0) { + error("No window."); + continue; + } + } + switch (c) { + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if ((w = window[c - '1']) == 0) { + error("%c: No such window.", c); + break; + } + setselwin(w); + if (checkproc(selwin) >= 0) + out = 1; + break; + case '%': + if ((w = getwin()) != 0) + setselwin(w); + break; + case ctrl('^'): + if (lastselwin != 0) { + setselwin(lastselwin); + if (checkproc(selwin) >= 0) + out = 1; + } else + error("No previous window."); + break; + case 'c': + if ((w = getwin()) != 0) + closewin(w); + break; + case 'w': + c_window(); + break; + case 'm': + if ((w = getwin()) != 0) + c_move(w); + break; + case 'M': + if ((w = getwin()) != 0) + movewin(w, w->ww_alt.t, w->ww_alt.l); + break; + case 's': + if ((w = getwin()) != 0) + c_size(w); + break; + case 'S': + if ((w = getwin()) != 0) + sizewin(w, w->ww_alt.nr, w->ww_alt.nc); + break; + case 'y': + c_yank(); + break; + case 'p': + c_put(); + break; + case ':': + c_colon(); + break; + case 'h': + (void) wwwrite(selwin, "\b", 1); + break; + case 'j': + (void) wwwrite(selwin, "\n", 1); + break; + case 'k': + (void) wwwrite(selwin, "\033A", 2); + break; + case 'l': + (void) wwwrite(selwin, "\033C", 2); + break; + case ctrl('e'): + wwscroll(selwin, 1); + break; + case ctrl('y'): + wwscroll(selwin, -1); + break; + case ctrl('d'): + wwscroll(selwin, selwin->ww_w.nr / 2); + break; + case ctrl('u'): + wwscroll(selwin, - selwin->ww_w.nr / 2); + break; + case ctrl('f'): + wwscroll(selwin, selwin->ww_w.nr); + break; + case ctrl('b'): + wwscroll(selwin, - selwin->ww_w.nr); + break; + case ctrl('s'): + stopwin(selwin); + break; + case ctrl('q'): + startwin(selwin); + break; + case ctrl('l'): + wwredraw(); + break; + case '?': + c_help(); + break; + case ctrl('['): + if (checkproc(selwin) >= 0) + out = 1; + break; + case ctrl('z'): + wwsuspend(); + break; + case 'q': + c_quit(); + break; + /* debugging stuff */ + case '&': + if (debug) { + c_debug(); + break; + } + default: + if (c == escapec) { + if (checkproc(selwin) >= 0) { + (void) write(selwin->ww_pty, + &escapec, 1); + out = 1; + } + } else { + if (!terse) + wwbell(); + error("Type ? for help."); + } + } + } + if (!quit) + setcmd(0); +} + +struct ww * +getwin() +{ + register int c; + struct ww *w = 0; + + if (!terse) + wwputs("Which window? ", cmdwin); + wwcurtowin(cmdwin); + while ((c = wwgetc()) < 0) + wwiomux(); + if (debug && c == 'c') + w = cmdwin; + else if (debug && c == 'f') + w = framewin; + else if (debug && c == 'b') + w = boxwin; + else if (c >= '1' && c < NWINDOW + '1') + w = window[c - '1']; + else if (c == '+') + w = selwin; + else if (c == '-') + w = lastselwin; + if (w == 0) + wwbell(); + if (!terse) + wwputc('\n', cmdwin); + return w; +} + +checkproc(w) +struct ww *w; +{ + if (w->ww_state != WWS_HASPROC) { + error("No process in window."); + return -1; + } + return 0; +} + +setcmd(new) +char new; +{ + if (new && !incmd) { + if (!terse) + wwadd(cmdwin, &wwhead); + if (selwin != 0) + wwcursor(selwin, 1); + wwcurwin = 0; + } else if (!new && incmd) { + if (!terse) { + wwdelete(cmdwin); + reframe(); + } + if (selwin != 0) + wwcursor(selwin, 0); + wwcurwin = selwin; + } + incmd = new; +} + +setterse(new) +char new; +{ + if (incmd) + if (new && !terse) { + wwdelete(cmdwin); + reframe(); + } else if (!new && terse) + wwadd(cmdwin, &wwhead); + terse = new; +} + +/* + * Set the current window. + */ +setselwin(w) +struct ww *w; +{ + if (selwin == w) + return; + if (selwin != 0) + lastselwin = selwin; + if ((selwin = w) != 0) + front(selwin, 1); +} diff --git a/usr.bin/window/cmd1.c b/usr.bin/window/cmd1.c new file mode 100644 index 0000000..df6deb9 --- /dev/null +++ b/usr.bin/window/cmd1.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "char.h" + +c_window() +{ + int col, row, xcol, xrow; + int id; + + if ((id = findid()) < 0) + return; + if (!terse) + wwputs("New window (upper left corner): ", cmdwin); + col = 0; + row = 1; + wwadd(boxwin, framewin->ww_back); + for (;;) { + wwbox(boxwin, row - 1, col - 1, 3, 3); + wwsetcursor(row, col); + while (wwpeekc() < 0) + wwiomux(); + switch (getpos(&row, &col, row > 1, 0, + wwnrow - 1, wwncol - 1)) { + case 3: + wwunbox(boxwin); + wwdelete(boxwin); + return; + case 2: + wwunbox(boxwin); + break; + case 1: + wwunbox(boxwin); + case 0: + continue; + } + break; + } + if (!terse) + wwputs("\nNew window (lower right corner): ", cmdwin); + xcol = col; + xrow = row; + for (;;) { + wwbox(boxwin, row - 1, col - 1, + xrow - row + 3, xcol - col + 3); + wwsetcursor(xrow, xcol); + while (wwpeekc() < 0) + wwiomux(); + switch (getpos(&xrow, &xcol, row, col, wwnrow - 1, wwncol - 1)) + { + case 3: + wwunbox(boxwin); + wwdelete(boxwin); + return; + case 2: + wwunbox(boxwin); + break; + case 1: + wwunbox(boxwin); + case 0: + continue; + } + break; + } + wwdelete(boxwin); + if (!terse) + wwputc('\n', cmdwin); + wwcurtowin(cmdwin); + (void) openwin(id, row, col, xrow-row+1, xcol-col+1, default_nline, + (char *) 0, 1, 1, default_shellfile, default_shell); +} + +getpos(row, col, minrow, mincol, maxrow, maxcol) +register int *row, *col; +int minrow, mincol; +int maxrow, maxcol; +{ + static int scount; + int count; + char c; + int oldrow = *row, oldcol = *col; + + while ((c = wwgetc()) >= 0) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + scount = scount * 10 + c - '0'; + continue; + } + count = scount ? scount : 1; + scount = 0; + switch (c) { + case 'h': + if ((*col -= count) < mincol) + *col = mincol; + break; + case 'H': + *col = mincol; + break; + case 'l': + if ((*col += count) > maxcol) + *col = maxcol; + break; + case 'L': + *col = maxcol; + break; + case 'j': + if ((*row += count) > maxrow) + *row = maxrow; + break; + case 'J': + *row = maxrow; + break; + case 'k': + if ((*row -= count) < minrow) + *row = minrow; + break; + case 'K': + *row = minrow; + break; + case ctrl('['): + if (!terse) + wwputs("\nCancelled. ", cmdwin); + return 3; + case '\r': + return 2; + default: + if (!terse) + wwputs("\nType [hjklHJKL] to move, return to enter position, escape to cancel.", cmdwin); + wwbell(); + } + } + return oldrow != *row || oldcol != *col; +} diff --git a/usr.bin/window/cmd2.c b/usr.bin/window/cmd2.c new file mode 100644 index 0000000..f6239e9 --- /dev/null +++ b/usr.bin/window/cmd2.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" + +char *help_shortcmd[] = { + "# Select window # and return to conversation mode", + "%# Select window # but stay in command mode", + "escape Return to conversation mode without changing window", + "^^ Return to conversation mode and change to previous window", + "c# Close window #", + "w Open a new window", + "m# Move window #", + "M# Move window # to its previous position", + "s# Change the size of window #", + "S# Change window # to its previous size", + "^Y Scroll up one line", + "^E Scroll down one line", + "^U Scroll up half a window", + "^D Scroll down half a window", + "^B Scroll up a full window", + "^F Scroll down a full window", + "h Move cursor left", + "j Move cursor down", + "k Move cursor up", + "l Move cursor right", + "y Yank", + "p Put", + "^S Stop output in current window", + "^Q Restart output in current window", + "^L Redraw screen", + "^Z Suspend", + "q Quit", + ": Enter a long command", + 0 +}; +char *help_longcmd[] = { + ":alias name string ... Make `name' an alias for `string ...'", + ":alias Show all aliases", + ":close # ... Close windows", + ":close all Close all windows", + ":cursor modes Set the cursor modes", + ":echo # string ... Print `string ...' in window #", + ":escape c Set escape character to `c'", + ":foreground # flag Make # a foreground window, if `flag' is true", + ":label # string Set label of window # to `string'", + ":list List all open windows", + ":default_nline lines Set default window buffer size to `lines'", + ":default_shell string ...", + " Set default shell to `string ...'", + ":default_smooth flag Set default smooth scroll flag", + ":select # Select window #", + ":smooth # flag Set window # to smooth scroll mode", + ":source filename Execute commands in `filename'", + ":terse flag Set terse mode", + ":unalias name Undefine `name' as an alias", + ":unset variable Deallocate `variable'", + ":variable List all variables", + ":window [row col nrow ncol nline label pty frame mapnl keepopen smooth shell]", + " Open a window at `row', `col' of size `nrow', `ncol',", + " with `nline' lines in the buffer, and `label'", + ":write # string ... Write `string ...' to window # as input", + 0 +}; + +c_help() +{ + register struct ww *w; + + if ((w = openiwin(wwnrow - 3, "Help")) == 0) { + error("Can't open help window: %s.", wwerror()); + return; + } + wwprintf(w, "The escape character is %c.\n", escapec); + wwprintf(w, "(# represents one of the digits from 1 to 9.)\n\n"); + if (help_print(w, "Short commands", help_shortcmd) >= 0) + (void) help_print(w, "Long commands", help_longcmd); + closeiwin(w); +} + +help_print(w, name, list) +register struct ww *w; +char *name; +register char **list; +{ + wwprintf(w, "%s:\n\n", name); + while (*list) + switch (more(w, 0)) { + case 0: + wwputs(*list++, w); + wwputc('\n', w); + break; + case 1: + wwprintf(w, "%s: (continued)\n\n", name); + break; + case 2: + return -1; + } + return more(w, 1) == 2 ? -1 : 0; +} + +c_quit() +{ + char oldterse = terse; + + setterse(0); + wwputs("Really quit [yn]? ", cmdwin); + wwcurtowin(cmdwin); + while (wwpeekc() < 0) + wwiomux(); + if (wwgetc() == 'y') { + wwputs("Yes", cmdwin); + quit++; + } else + wwputc('\n', cmdwin); + setterse(!quit && oldterse); +} diff --git a/usr.bin/window/cmd3.c b/usr.bin/window/cmd3.c new file mode 100644 index 0000000..950ddf6 --- /dev/null +++ b/usr.bin/window/cmd3.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd3.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "string.h" + +setescape(esc) +register char *esc; +{ + if (*esc == '^') { + if (esc[1] != 0) + escapec = esc[1] & 0x1f; + else + escapec = '^'; + } else + escapec = *esc; +} + +setlabel(w, label) +register struct ww *w; +char *label; +{ + if (w->ww_label != 0) + str_free(w->ww_label); + if ((w->ww_label = str_cpy(label)) == 0) + return -1; + return 0; +} diff --git a/usr.bin/window/cmd4.c b/usr.bin/window/cmd4.c new file mode 100644 index 0000000..5dca8f8 --- /dev/null +++ b/usr.bin/window/cmd4.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd4.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" + +c_colon() +{ + char oldterse = terse; + char buf[512]; + + setterse(0); + wwputc(':', cmdwin); + wwgets(buf, wwncol - 3, cmdwin); + wwputc('\n', cmdwin); + wwcurtowin(cmdwin); + setterse(oldterse); + if (dolongcmd(buf, (struct value *)0, 0) < 0) + error("Out of memory."); +} diff --git a/usr.bin/window/cmd5.c b/usr.bin/window/cmd5.c new file mode 100644 index 0000000..456fdb9 --- /dev/null +++ b/usr.bin/window/cmd5.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd5.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" + +/* + * Window movement. + */ + +c_move(w) +register struct ww *w; +{ + int col, row; + int mincol, minrow; + int maxcol, maxrow; + int curcol, currow; + + if (!terse) + wwputs("New window position: ", cmdwin); + col = w->ww_w.l; + row = w->ww_w.t; + wwadd(boxwin, framewin->ww_back); + for (;;) { + wwbox(boxwin, row - 1, col - 1, w->ww_w.nr + 2, w->ww_w.nc + 2); + getminmax(row, w->ww_w.nr, 1, wwnrow, + &currow, &minrow, &maxrow); + getminmax(col, w->ww_w.nc, 0, wwncol, + &curcol, &mincol, &maxcol); + wwsetcursor(currow, curcol); + while (wwpeekc() < 0) + wwiomux(); + switch (getpos(&row, &col, minrow, mincol, maxrow, maxcol)) { + case 3: + wwunbox(boxwin); + wwdelete(boxwin); + return; + case 2: + wwunbox(boxwin); + break; + case 1: + wwunbox(boxwin); + case 0: + continue; + } + break; + } + wwdelete(boxwin); + if (!terse) + wwputc('\n', cmdwin); + wwcurtowin(cmdwin); + movewin(w, row, col); +} + +movewin(w, row, col) +register struct ww *w; +{ + struct ww *back = w->ww_back; + + w->ww_alt.t = w->ww_w.t; + w->ww_alt.l = w->ww_w.l; + wwdelete(w); + wwmove(w, row, col); + wwadd(w, back); + reframe(); +} + +/* + * Weird stufff, don't ask. + */ +getminmax(x, n, a, b, curx, minx, maxx) +register x, n, a, b; +int *curx, *minx, *maxx; +{ + if (x < 0) + *curx = x + n - 1; + else + *curx = x; + + if (x <= a) + *minx = 1 - n; + else if (x <= b - n) + *minx = a; + else + *minx = b - n; + + if (x >= b - n) + *maxx = b - 1; + else if (x >= a) + *maxx = b - n; + else + *maxx = a; +} diff --git a/usr.bin/window/cmd6.c b/usr.bin/window/cmd6.c new file mode 100644 index 0000000..fc85485 --- /dev/null +++ b/usr.bin/window/cmd6.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd6.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "string.h" +#include "char.h" + +/* + * Debugging commands. + */ + +c_debug() +{ + register struct ww *w; + + if (!terse) + wwputs("[m(smap) n(ns) o(os) s(string) v(nvis) w(win)]? ", cmdwin); + wwcurtowin(cmdwin); + while (wwpeekc() < 0) + wwiomux(); + if (!terse) + wwputc('\n', cmdwin); + switch (wwgetc()) { + case 'm': + wwdumpsmap(); + break; + case 'n': + wwdumpns(); + break; + case 'o': + wwdumpos(); + break; + case 's': + debug_str(); + break; + case 'v': + if ((w = getwin()) != 0) + wwdumpnvis(w); + break; + case 'w': + if ((w = getwin()) != 0) + wwdumpwin(w); + break; + default: + wwbell(); + } +} + +#ifdef STR_DEBUG +debug_str() +{ + register struct ww *w; + struct string *s; + + if ((w = openiwin(wwnrow - 3, "Allocated Strings")) == 0) { + error("Can't open string window: %s.", wwerror()); + return; + } + for (s = str_head.s_forw; s != &str_head; s = s->s_forw) { + if (more(w, 0) == 2) + goto out; + wwprintf(w, "(0x%x)\t\"%s\"\n", s->s_data, s->s_data); + } + waitnl(w); +out: + closeiwin(w); +} +#else +debug_str() +{ + error("No string debugging."); +} +#endif diff --git a/usr.bin/window/cmd7.c b/usr.bin/window/cmd7.c new file mode 100644 index 0000000..6bd4c4e --- /dev/null +++ b/usr.bin/window/cmd7.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)cmd7.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "string.h" + +/* + * Window size. + */ + +c_size(w) +register struct ww *w; +{ + int col, row; + + if (!terse) + wwputs("New window size (lower right corner): ", cmdwin); + col = MIN(w->ww_w.r, wwncol) - 1; + row = MIN(w->ww_w.b, wwnrow) - 1; + wwadd(boxwin, framewin->ww_back); + for (;;) { + wwbox(boxwin, w->ww_w.t - 1, w->ww_w.l - 1, + row - w->ww_w.t + 3, col - w->ww_w.l + 3); + wwsetcursor(row, col); + while (wwpeekc() < 0) + wwiomux(); + switch (getpos(&row, &col, w->ww_w.t, w->ww_w.l, + wwnrow - 1, wwncol - 1)) { + case 3: + wwunbox(boxwin); + wwdelete(boxwin); + return; + case 2: + wwunbox(boxwin); + break; + case 1: + wwunbox(boxwin); + case 0: + continue; + } + break; + } + wwdelete(boxwin); + if (!terse) + wwputc('\n', cmdwin); + wwcurtowin(cmdwin); + sizewin(w, row - w->ww_w.t + 1, col - w->ww_w.l + 1); +} + +/* + * Yank and put + */ + +struct yb { + char *line; + int length; + struct yb *link; +}; +struct yb *yb_head, *yb_tail; + +c_yank() +{ + struct ww *w = selwin; + int col1, row1; + int col2, row2; + int r, c; + + if (!terse) + wwputs("Yank starting position: ", cmdwin); + wwcursor(w, 0); + row1 = w->ww_cur.r; + col1 = w->ww_cur.c; + for (;;) { + wwsetcursor(row1, col1); + while (wwpeekc() < 0) + wwiomux(); + switch (getpos(&row1, &col1, w->ww_i.t, w->ww_i.l, + w->ww_i.b - 1, w->ww_i.r - 1)) { + case 3: + goto out; + case 2: + break; + case 1: + case 0: + continue; + } + break; + } + if (!terse) + wwputs("\nYank ending position: ", cmdwin); + row2 = row1; + col2 = col1; + for (;;) { + wwsetcursor(row2, col2); + while (wwpeekc() < 0) + wwiomux(); + r = row2; + c = col2; + switch (getpos(&row2, &col2, w->ww_i.t, w->ww_i.l, + w->ww_i.b - 1, w->ww_i.r - 1)) { + case 3: + yank_highlight(row1, col1, r, c); + goto out; + case 2: + break; + case 1: + yank_highlight(row1, col1, r, c); + yank_highlight(row1, col1, row2, col2); + case 0: + continue; + } + break; + } + if (row2 < row1 || row2 == row1 && col2 < col1) { + r = row1; + c = col1; + row1 = row2; + col1 = col2; + row2 = r; + col2 = c; + } + unyank(); + c = col1; + for (r = row1; r < row2; r++) { + yank_line(r, c, w->ww_b.r); + c = w->ww_b.l; + } + yank_line(r, c, col2); + yank_highlight(row1, col1, row2, col2); + if (!terse) + wwputc('\n', cmdwin); +out: + wwcursor(w, 1); +} + +yank_highlight(row1, col1, row2, col2) +{ + struct ww *w = selwin; + int r, c; + + if ((wwavailmodes & WWM_REV) == 0) + return; + if (row2 < row1 || row2 == row1 && col2 < col1) { + r = row1; + c = col1; + row1 = row2; + col1 = col2; + row2 = r; + col2 = c; + } + c = col1; + for (r = row1; r < row2; r++) { + yank_highlight_line(r, c, w->ww_b.r); + c = w->ww_b.l; + } + yank_highlight_line(r, c, col2); +} + +yank_highlight_line(r, c, cend) +{ + struct ww *w = selwin; + char *win; + + if (r < w->ww_i.t || r >= w->ww_i.b) + return; + if (c < w->ww_i.l) + c = w->ww_i.l; + if (cend >= w->ww_i.r) + cend = w->ww_i.r; + for (win = w->ww_win[r] + c; c < cend; c++, win++) { + *win ^= WWM_REV; + if (wwsmap[r][c] == w->ww_index) { + if (*win == 0) + w->ww_nvis[r]++; + else if (*win == WWM_REV) + w->ww_nvis[r]--; + wwns[r][c].c_m ^= WWM_REV; + wwtouched[r] |= WWU_TOUCHED; + } + } +} + +unyank() +{ + struct yb *yp, *yq; + + for (yp = yb_head; yp; yp = yq) { + yq = yp->link; + str_free(yp->line); + free((char *) yp); + } + yb_head = yb_tail = 0; +} + +yank_line(r, c, cend) +{ + struct yb *yp; + int nl = 0; + int n; + union ww_char *bp; + char *cp; + + if (c == cend) + return; + if ((yp = (struct yb *) malloc(sizeof *yp)) == 0) + return; + yp->link = 0; + nl = cend == selwin->ww_b.r; + bp = selwin->ww_buf[r]; + for (cend--; cend >= c; cend--) + if (bp[cend].c_c != ' ') + break; + yp->length = n = cend - c + 1; + if (nl) + yp->length++; + yp->line = str_alloc(yp->length + 1); + for (bp += c, cp = yp->line; --n >= 0;) + *cp++ = bp++->c_c; + if (nl) + *cp++ = '\n'; + *cp = 0; + if (yb_head) + yb_tail = yb_tail->link = yp; + else + yb_head = yb_tail = yp; +} + +c_put() +{ + struct yb *yp; + + for (yp = yb_head; yp; yp = yp->link) + (void) write(selwin->ww_pty, yp->line, yp->length); +} diff --git a/usr.bin/window/compress.c b/usr.bin/window/compress.c new file mode 100644 index 0000000..ccac095 --- /dev/null +++ b/usr.bin/window/compress.c @@ -0,0 +1,899 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)compress.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + + /* special */ +#include +#include +int cc_trace = 0; +FILE *cc_trace_fp; + + /* tunable parameters */ + +int cc_reverse = 1; +int cc_sort = 0; +int cc_chop = 0; + +int cc_token_max = 8; /* <= TOKEN_MAX */ +int cc_token_min = 2; /* > tt.tt_put_token_cost */ +int cc_npass0 = 1; +int cc_npass1 = 1; + +int cc_bufsize = 1024 * 3; /* XXX, or 80 * 24 * 2 */ + +int cc_ntoken = 8192; + +#define cc_weight XXX +#ifndef cc_weight +int cc_weight = 0; +#endif + +#define TOKEN_MAX 16 + +struct cc { + char string[TOKEN_MAX]; + char length; + char flag; +#ifndef cc_weight + short weight; +#endif + long time; /* time last seen */ + short bcount; /* count in this buffer */ + short ccount; /* count in compression */ + short places; /* places in the buffer */ + short code; /* token code */ + struct cc *qforw, *qback; + struct cc *hforw, **hback; +}; + +short cc_thresholds[TOKEN_MAX + 1]; +#define thresh(length) (cc_thresholds[length]) +#define threshp(code, count, length) \ + ((code) >= 0 || (short) (count) >= cc_thresholds[length]) + +#ifndef cc_weight +short cc_wthresholds[TOKEN_MAX + 1]; +#define wthresh(length) (cc_wthresholds[length]) +#define wthreshp(weight, length) ((short) (weight) >= cc_wthresholds[length]) +#else +#define wthreshp(weight, length) (0) +#endif + +#ifndef cc_weight +short cc_wlimits[TOKEN_MAX + 1]; +#define wlimit(length) (cc_wlimits[length]) +#endif + +#define put_token_score(length) ((length) - tt.tt_put_token_cost) + +int cc_score_adjustments[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */ +#define score_adjust(score, p) \ + do { \ + int length = (p)->length; \ + int ccount = (p)->ccount; \ + if (threshp((p)->code, ccount, length) || \ + wthreshp((p)->weight, length)) /* XXX */ \ + (score) -= length - tt.tt_put_token_cost; \ + else \ + (score) += cc_score_adjustments[length][ccount]; \ + } while (0) + +int cc_initial_scores[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */ + +struct cc cc_q0a, cc_q0b, cc_q1a, cc_q1b; + +#define qinsert(p1, p2) \ + do { \ + register struct cc *forw = (p1)->qforw; \ + register struct cc *back = (p1)->qback; \ + back->qforw = forw; \ + forw->qback = back; \ + forw = (p2)->qforw; \ + (p1)->qforw = forw; \ + forw->qback = (p1); \ + (p2)->qforw = (p1); \ + (p1)->qback = (p2); \ + } while (0) + +#define qinsertq(q, p) \ + ((q)->qforw == (q) ? 0 : \ + ((q)->qback->qforw = (p)->qforw, \ + (p)->qforw->qback = (q)->qback, \ + (q)->qforw->qback = (p), \ + (p)->qforw = (q)->qforw, \ + (q)->qforw = (q), \ + (q)->qback = (q))) + +#define H (14) +#define HSIZE (1 << H) +#define hash(h, c) ((((h) >> H - 8 | (h) << 8) ^ (c)) & HSIZE - 1) + +char *cc_buffer; +struct cc **cc_output; /* the output array */ +short *cc_places[TOKEN_MAX + 1]; +short *cc_hashcodes; /* for computing hashcodes */ +struct cc **cc_htab; /* the hash table */ +struct cc **cc_tokens; /* holds all the active tokens */ +struct cc_undo { + struct cc **pos; + struct cc *val; +} *cc_undo; + +long cc_time, cc_time0; + +char *cc_tt_ob, *cc_tt_obe; + +ccinit() +{ + register i, j; + register struct cc *p; + + if (tt.tt_token_max > cc_token_max) + tt.tt_token_max = cc_token_max; + if (tt.tt_token_min < cc_token_min) + tt.tt_token_min = cc_token_min; + if (tt.tt_token_min > tt.tt_token_max) { + tt.tt_ntoken = 0; + return 0; + } + if (tt.tt_ntoken > cc_ntoken / 2) /* not likely */ + tt.tt_ntoken = cc_ntoken / 2; +#define C(x) (sizeof (x) / sizeof *(x)) + for (i = 0; i < C(cc_thresholds); i++) { + int h = i - tt.tt_put_token_cost; + if (h > 0) + cc_thresholds[i] = + (tt.tt_set_token_cost + 1 + h - 1) / h + 1; + else + cc_thresholds[i] = 0; + } + for (i = 0; i < C(cc_score_adjustments); i++) { + int t = cc_thresholds[i]; + for (j = 0; j < C(*cc_score_adjustments); j++) { + if (j >= t) + cc_score_adjustments[i][j] = + - (i - tt.tt_put_token_cost); + else if (j < t - 1) + cc_score_adjustments[i][j] = 0; + else + /* + * cost now is + * length * (ccount + 1) a + * cost before was + * set-token-cost + length + + * ccount * put-token-cost b + * the score adjustment is (b - a) + */ + cc_score_adjustments[i][j] = + tt.tt_set_token_cost + i + + j * tt.tt_put_token_cost - + i * (j + 1); + if (j >= t) + cc_initial_scores[i][j] = 0; + else + /* + * - (set-token-cost + + * (length - put-token-cost) - + * (length - put-token-cost) * ccount) + */ + cc_initial_scores[i][j] = + - (tt.tt_set_token_cost + + (i - tt.tt_put_token_cost) - + (i - tt.tt_put_token_cost) * j); + } + } +#ifndef cc_weight + for (i = 1; i < C(cc_wthresholds); i++) { + cc_wthresholds[i] = + ((tt.tt_set_token_cost + tt.tt_put_token_cost) / i + + i / 5 + 1) * + cc_weight + 1; + cc_wlimits[i] = cc_wthresholds[i] + cc_weight; + } +#endif +#undef C + if ((cc_output = (struct cc **) + malloc((unsigned) cc_bufsize * sizeof *cc_output)) == 0) + goto nomem; + if ((cc_hashcodes = (short *) + malloc((unsigned) cc_bufsize * sizeof *cc_hashcodes)) == 0) + goto nomem; + if ((cc_htab = (struct cc **) malloc(HSIZE * sizeof *cc_htab)) == 0) + goto nomem; + if ((cc_tokens = (struct cc **) + malloc((unsigned) + (cc_ntoken + tt.tt_token_max - tt.tt_token_min + 1) * + sizeof *cc_tokens)) == 0) + goto nomem; + if ((cc_undo = (struct cc_undo *) + malloc((unsigned) cc_bufsize * sizeof *cc_undo)) == 0) + goto nomem; + for (i = tt.tt_token_min; i <= tt.tt_token_max; i++) + if ((cc_places[i] = (short *) + malloc((unsigned) cc_bufsize * sizeof **cc_places)) == 0) + goto nomem; + cc_q0a.qforw = cc_q0a.qback = &cc_q0a; + cc_q0b.qforw = cc_q0b.qback = &cc_q0b; + cc_q1a.qforw = cc_q1a.qback = &cc_q1a; + cc_q1b.qforw = cc_q1b.qback = &cc_q1b; + if ((p = (struct cc *) malloc((unsigned) cc_ntoken * sizeof *p)) == 0) + goto nomem; + for (i = 0; i < tt.tt_ntoken; i++) { + p->code = i; + p->time = -1; + p->qback = cc_q0a.qback; + p->qforw = &cc_q0a; + p->qback->qforw = p; + cc_q0a.qback = p; + p++; + } + for (; i < cc_ntoken; i++) { + p->code = -1; + p->time = -1; + p->qback = cc_q1a.qback; + p->qforw = &cc_q1a; + p->qback->qforw = p; + cc_q1a.qback = p; + p++; + } + cc_tt_ob = tt_ob; + cc_tt_obe = tt_obe; + if ((cc_buffer = malloc((unsigned) cc_bufsize)) == 0) + goto nomem; + return 0; +nomem: + wwerrno = WWE_NOMEM; + return -1; +} + +ccstart() +{ + int ccflush(); + + ttflush(); + tt_obp = tt_ob = cc_buffer; + tt_obe = tt_ob + cc_bufsize; + tt.tt_flush = ccflush; + if (cc_trace) { + cc_trace_fp = fopen("window-trace", "a"); + (void) fcntl(fileno(cc_trace_fp), F_SETFD, 1); + } + ccreset(); +} + +ccreset() +{ + register struct cc *p; + + bzero((char *) cc_htab, HSIZE * sizeof *cc_htab); + for (p = cc_q0a.qforw; p != &cc_q0a; p = p->qforw) + p->hback = 0; + for (p = cc_q1a.qforw; p != &cc_q1a; p = p->qforw) + p->hback = 0; +} + +ccend() +{ + + ttflush(); + tt_obp = tt_ob = cc_tt_ob; + tt_obe = cc_tt_obe; + tt.tt_flush = 0; + if (cc_trace_fp != NULL) { + (void) fclose(cc_trace_fp); + cc_trace_fp = NULL; + } +} + +ccflush() +{ + int bufsize = tt_obp - tt_ob; + int n; + + if (tt_ob != cc_buffer) + abort(); + if (cc_trace_fp != NULL) { + (void) fwrite(tt_ob, 1, bufsize, cc_trace_fp); + (void) putc(-1, cc_trace_fp); + } + tt.tt_flush = 0; + (*tt.tt_compress)(1); + if (bufsize < tt.tt_token_min) { + ttflush(); + goto out; + } + tt_obp = tt_ob = cc_tt_ob; + tt_obe = cc_tt_obe; + cc_time0 = cc_time; + cc_time += bufsize; + n = cc_sweep_phase(cc_buffer, bufsize, cc_tokens); + cc_compress_phase(cc_output, bufsize, cc_tokens, n); + cc_output_phase(cc_buffer, cc_output, bufsize); + ttflush(); + tt_obp = tt_ob = cc_buffer; + tt_obe = cc_buffer + cc_bufsize; +out: + (*tt.tt_compress)(0); + tt.tt_flush = ccflush; +} + +cc_sweep_phase(buffer, bufsize, tokens) + char *buffer; + struct cc **tokens; +{ + register struct cc **pp = tokens; + register i, n; +#ifdef STATS + int nn, ii; +#endif + +#ifdef STATS + if (verbose >= 0) + time_begin(); + if (verbose > 0) + printf("Sweep:"); +#endif + cc_sweep0(buffer, bufsize, tt.tt_token_min - 1); +#ifdef STATS + ntoken_stat = 0; + nn = 0; + ii = 0; +#endif + for (i = tt.tt_token_min; i <= tt.tt_token_max; i++) { +#ifdef STATS + if (verbose > 0) { + if (ii > 7) { + printf("\n "); + ii = 0; + } + ii++; + printf(" (%d", i); + (void) fflush(stdout); + } +#endif + n = cc_sweep(buffer, bufsize, pp, i); + pp += n; +#ifdef STATS + if (verbose > 0) { + if (--n > 0) { + printf(" %d", n); + nn += n; + } + putchar(')'); + } +#endif + } + qinsertq(&cc_q1b, &cc_q1a); +#ifdef STATS + if (verbose > 0) + printf("\n %d tokens, %d candidates\n", + ntoken_stat, nn); + if (verbose >= 0) + time_end(); +#endif + return pp - tokens; +} + +cc_sweep0(buffer, n, length) + char *buffer; +{ + register char *p; + register short *hc; + register i; + register short c; + register short pc = tt.tt_padc; + + /* n and length are at least 1 */ + p = buffer++; + hc = cc_hashcodes; + i = n; + do { + if ((*hc++ = *p++) == pc) + hc[-1] = -1; + } while (--i); + while (--length) { + p = buffer++; + hc = cc_hashcodes; + for (i = n--; --i;) { + if ((c = *p++) == pc || *hc < 0) + c = -1; + else + c = hash(*hc, c); + *hc++ = c; + } + } +} + +cc_sweep(buffer, bufsize, tokens, length) + char *buffer; + struct cc **tokens; + register length; +{ + register struct cc *p; + register char *cp; + register i; + short *hc; + short *places = cc_places[length]; + struct cc **pp = tokens; + short threshold = thresh(length); +#ifndef cc_weight + short wthreshold = wthresh(length); + short limit = wlimit(length); +#endif + int time; + short pc = tt.tt_padc; + + i = length - 1; + bufsize -= i; + cp = buffer + i; + hc = cc_hashcodes; + time = cc_time0; + for (i = 0; i < bufsize; i++, time++) { + struct cc **h; + + { + register short *hc1 = hc; + register short c = *cp++; + register short hh; + if ((hh = *hc1) < 0 || c == pc) { + *hc1++ = -1; + hc = hc1; + continue; + } + h = cc_htab + (*hc1++ = hash(hh, c)); + hc = hc1; + } + for (p = *h; p != 0; p = p->hforw) + if (p->length == (char) length) { + register char *p1 = p->string; + register char *p2 = cp - length; + register n = length; + do + if (*p1++ != *p2++) + goto fail; + while (--n); + break; + fail:; + } + if (p == 0) { + p = cc_q1a.qback; + if (p == &cc_q1a || + p->time >= cc_time0 && p->length == (char) length) + continue; + if (p->hback != 0) + if ((*p->hback = p->hforw) != 0) + p->hforw->hback = p->hback; + { + register char *p1 = p->string; + register char *p2 = cp - length; + register n = length; + do + *p1++ = *p2++; + while (--n); + } + p->length = length; +#ifndef cc_weight + p->weight = cc_weight; +#endif + p->time = time; + p->bcount = 1; + p->ccount = 0; + p->flag = 0; + if ((p->hforw = *h) != 0) + p->hforw->hback = &p->hforw; + *h = p; + p->hback = h; + qinsert(p, &cc_q1a); + places[i] = -1; + p->places = i; +#ifdef STATS + ntoken_stat++; +#endif + } else if (p->time < cc_time0) { +#ifndef cc_weight + if ((p->weight += p->time - time) < 0) + p->weight = cc_weight; + else if ((p->weight += cc_weight) > limit) + p->weight = limit; +#endif + p->time = time; + p->bcount = 1; + p->ccount = 0; + if (p->code >= 0) { + p->flag = 1; + *pp++ = p; + } else +#ifndef cc_weight + if (p->weight >= wthreshold) { + p->flag = 1; + *pp++ = p; + qinsert(p, &cc_q1b); + } else +#endif + { + p->flag = 0; + qinsert(p, &cc_q1a); + } + places[i] = -1; + p->places = i; +#ifdef STATS + ntoken_stat++; +#endif + } else if (p->time + length > time) { + /* + * overlapping token, don't count as two and + * don't update time, but do adjust weight to offset + * the difference + */ +#ifndef cc_weight + if (cc_weight != 0) { /* XXX */ + p->weight += time - p->time; + if (!p->flag && p->weight >= wthreshold) { + p->flag = 1; + *pp++ = p; + qinsert(p, &cc_q1b); + } + } +#endif + places[i] = p->places; + p->places = i; + } else { +#ifndef cc_weight + if ((p->weight += p->time - time) < 0) + p->weight = cc_weight; + else if ((p->weight += cc_weight) > limit) + p->weight = limit; +#endif + p->time = time; + p->bcount++; + if (!p->flag && + /* code must be < 0 if flag false here */ + (p->bcount >= threshold +#ifndef cc_weight + || p->weight >= wthreshold +#endif + )) { + p->flag = 1; + *pp++ = p; + qinsert(p, &cc_q1b); + } + places[i] = p->places; + p->places = i; + } + } + if ((i = pp - tokens) > 0) { + *pp = 0; + if (cc_reverse) + cc_sweep_reverse(tokens, places); + if (cc_sort && i > 1) { + int cc_token_compare(); + qsort((char *) tokens, i, sizeof *tokens, + cc_token_compare); + } + if (cc_chop) { + if ((i = i * cc_chop / 100) == 0) + i = 1; + tokens[i] = 0; + } + i++; + } + return i; +} + +cc_sweep_reverse(pp, places) + register struct cc **pp; + register short *places; +{ + register struct cc *p; + register short front, back, t; + + while ((p = *pp++) != 0) { + back = -1; + t = p->places; + /* the list is never empty */ + do { + front = places[t]; + places[t] = back; + back = t; + } while ((t = front) >= 0); + p->places = back; + } +} + +cc_compress_phase(output, bufsize, tokens, ntoken) + struct cc **output; + struct cc **tokens; +{ + register i; + + bzero((char *) output, bufsize * sizeof *output); + for (i = 0; i < cc_npass0; i++) + cc_compress_phase1(output, tokens, ntoken, 0); + for (i = 0; i < cc_npass1; i++) + cc_compress_phase1(output, tokens, ntoken, 1); + cc_compress_cleanup(output, bufsize); +} + +cc_compress_phase1(output, tokens, ntoken, flag) + register struct cc **output; + struct cc **tokens; +{ + register struct cc **pp; +#ifdef STATS + register int i = 0; + int nt = 0, cc = 0, nc = 0; +#endif + +#ifdef STATS + if (verbose >= 0) + time_begin(); + if (verbose > 0) + printf("Compress:"); +#endif + pp = tokens; + while (pp < tokens + ntoken) { +#ifdef STATS + if (verbose > 0) { + ntoken_stat = 0; + ccount_stat = 0; + ncover_stat = 0; + if (i > 2) { + printf("\n "); + i = 0; + } + i++; + printf(" (%d", (*pp)->length); + (void) fflush(stdout); + } +#endif + pp += cc_compress(output, pp, flag); +#ifdef STATS + if (verbose > 0) { + printf(" %dt %du %dc)", ntoken_stat, ccount_stat, + ncover_stat); + nt += ntoken_stat; + cc += ccount_stat; + nc += ncover_stat; + } +#endif + } +#ifdef STATS + if (verbose > 0) + printf("\n total: (%dt %du %dc)\n", nt, cc, nc); + if (verbose >= 0) + time_end(); +#endif +} + +cc_compress_cleanup(output, bufsize) + register struct cc **output; +{ + register struct cc **end; + + /* the previous output phase may have been interrupted */ + qinsertq(&cc_q0b, &cc_q0a); + for (end = output + bufsize; output < end;) { + register struct cc *p; + register length; + if ((p = *output) == 0) { + output++; + continue; + } + length = p->length; + if (!p->flag) { + } else if (p->code >= 0) { + qinsert(p, &cc_q0b); + p->flag = 0; + } else if (p->ccount == 0) { + *output = 0; + } else if (p->ccount >= thresh(length) +#ifndef cc_weight + || wthreshp(p->weight, length) +#endif + ) { + p->flag = 0; + } else { + p->ccount = 0; + *output = 0; + } + output += length; + } +} + +cc_compress(output, tokens, flag) + struct cc **output; + struct cc **tokens; + char flag; +{ + struct cc **pp = tokens; + register struct cc *p = *pp++; + int length = p->length; + int threshold = thresh(length); +#ifndef cc_weight + short wthreshold = wthresh(length); +#endif + short *places = cc_places[length]; + int *initial_scores = cc_initial_scores[length]; + int initial_score0 = put_token_score(length); + + do { + int score; + register struct cc_undo *undop; + int ccount; +#ifdef STATS + int ncover; +#endif + int i; + + ccount = p->ccount; + if ((short) ccount >= p->bcount) + continue; + if (p->code >= 0 || ccount >= threshold) + score = 0; +#ifndef cc_weight + else if (p->weight >= wthreshold) + /* allow one fewer match than normal */ + /* XXX, should adjust for ccount */ + score = - tt.tt_set_token_cost; +#endif + else + score = initial_scores[ccount]; + undop = cc_undo; +#ifdef STATS + ncover = 0; +#endif + for (i = p->places; i >= 0; i = places[i]) { + register struct cc **jp; + register struct cc *x; + register struct cc **ip = output + i; + register score0 = initial_score0; + struct cc **iip = ip + length; + struct cc_undo *undop1 = undop; + + if ((x = *(jp = ip)) != 0) + goto z; + while (--jp >= output) + if ((x = *jp) != 0) { + if (jp + x->length > ip) + goto z; + break; + } + jp = ip + 1; + while (jp < iip) { + if ((x = *jp) == 0) { + jp++; + continue; + } + z: + if (x == p) + goto undo; +#ifdef STATS + ncover++; +#endif + undop->pos = jp; + undop->val = x; + undop++; + *jp = 0; + x->ccount--; + score_adjust(score0, x); + if (score0 < 0 && flag) + goto undo; + jp += x->length; + } + undop->pos = ip; + undop->val = 0; + undop++; + *ip = p; + ccount++; + score += score0; + continue; + undo: + while (--undop >= undop1) + if (*undop->pos = x = undop->val) + x->ccount++; + undop++; + } + if (score > 0) { +#ifdef STATS + ccount_stat += ccount - p->ccount; + ntoken_stat++; + ncover_stat += ncover; +#endif + p->ccount = ccount; + } else { + register struct cc_undo *u = cc_undo; + while (--undop >= u) { + register struct cc *x; + if (*undop->pos = x = undop->val) + x->ccount++; + } + } + } while ((p = *pp++) != 0); + return pp - tokens; +} + +cc_output_phase(buffer, output, bufsize) + register char *buffer; + register struct cc **output; + register bufsize; +{ + register i; + register struct cc *p, *p1; + + for (i = 0; i < bufsize;) { + if ((p = output[i]) == 0) { + ttputc(buffer[i]); + i++; + } else if (p->code >= 0) { + if (--p->ccount == 0) + qinsert(p, &cc_q0a); + (*tt.tt_put_token)(p->code, p->string, p->length); + wwntokuse++; + wwntoksave += put_token_score(p->length); + i += p->length; + } else if ((p1 = cc_q0a.qback) != &cc_q0a) { + p->code = p1->code; + p1->code = -1; + qinsert(p1, &cc_q1a); + if (--p->ccount == 0) + qinsert(p, &cc_q0a); + else + qinsert(p, &cc_q0b); + (*tt.tt_set_token)(p->code, p->string, p->length); + wwntokdef++; + wwntoksave -= tt.tt_set_token_cost; + i += p->length; + } else { + p->ccount--; + ttwrite(p->string, p->length); + wwntokbad++; + i += p->length; + } + } + wwntokc += bufsize; +} + +cc_token_compare(p1, p2) + struct cc **p1, **p2; +{ + return (*p2)->bcount - (*p1)->bcount; +} diff --git a/usr.bin/window/context.c b/usr.bin/window/context.c new file mode 100644 index 0000000..cd43cdb --- /dev/null +++ b/usr.bin/window/context.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)context.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "value.h" +#include "string.h" +#include "context.h" +#include + +/* + * Context push/pop for nested command files. + */ + +char *malloc(); + +cx_alloc() +{ + register struct context *xp; + + if (cx.x_type != 0) { + xp = (struct context *) + malloc((unsigned) sizeof (struct context)); + if (xp == 0) + return -1; + *xp = cx; + cx.x_link = xp; + cx.x_type = 0; + } + cx.x_erred = 0; + cx.x_synerred = 0; + cx.x_abort = 0; + return 0; +} + +cx_free() +{ + struct context *xp; + + if ((xp = cx.x_link) != 0) { + cx = *xp; + free((char *)xp); + } else + cx.x_type = 0; +} + +cx_beginfile(filename) +char *filename; +{ + if (cx_alloc() < 0) + return -1; + cx.x_type = X_FILE; + if ((cx.x_filename = str_cpy(filename)) == 0) + goto bad; + cx.x_fp = fopen(filename, "r"); + if (cx.x_fp == 0) + goto bad; + (void) fcntl(fileno(cx.x_fp), F_SETFD, 1); + cx.x_bol = 1; + cx.x_lineno = 0; + cx.x_errwin = 0; + cx.x_noerr = 0; + return 0; +bad: + if (cx.x_filename != 0) + str_free(cx.x_filename); + cx_free(); + return -1; +} + +cx_beginbuf(buf, arg, narg) +char *buf; +struct value *arg; +int narg; +{ + if (cx_alloc() < 0) + return -1; + cx.x_type = X_BUF; + cx.x_bufp = cx.x_buf = buf; + cx.x_arg = arg; + cx.x_narg = narg; + return 0; +} + +cx_end() +{ + switch (cx.x_type) { + case X_BUF: + break; + case X_FILE: + (void) fclose(cx.x_fp); + str_free(cx.x_filename); + break; + } + cx_free(); +} diff --git a/usr.bin/window/context.h b/usr.bin/window/context.h new file mode 100644 index 0000000..4863abe --- /dev/null +++ b/usr.bin/window/context.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)context.h 8.1 (Berkeley) 6/6/93 + */ + +#include + +struct context { + struct context *x_link; /* nested contexts */ + char x_type; /* tag for union */ + union { + struct { /* input is a file */ + char *X_filename; /* input file name */ + FILE *X_fp; /* input stream */ + short X_lineno; /* current line number */ + char X_bol; /* at beginning of line */ + char X_noerr; /* don't report errors */ + struct ww *X_errwin; /* error window */ + } x_f; + struct { /* input is a buffer */ + char *X_buf; /* input buffer */ + char *X_bufp; /* current position in buf */ + struct value *X_arg; /* argument for alias */ + int X_narg; /* number of arguments */ + } x_b; + } x_un; + /* holding place for current token */ + int x_token; /* the token */ + struct value x_val; /* values associated with token */ + /* parser error flags */ + unsigned x_erred :1; /* had an error */ + unsigned x_synerred :1; /* had syntax error */ + unsigned x_abort :1; /* fatal error */ +}; +#define x_buf x_un.x_b.X_buf +#define x_bufp x_un.x_b.X_bufp +#define x_arg x_un.x_b.X_arg +#define x_narg x_un.x_b.X_narg +#define x_filename x_un.x_f.X_filename +#define x_fp x_un.x_f.X_fp +#define x_lineno x_un.x_f.X_lineno +#define x_bol x_un.x_f.X_bol +#define x_errwin x_un.x_f.X_errwin +#define x_noerr x_un.x_f.X_noerr + + /* x_type values, 0 is reserved */ +#define X_FILE 1 /* input is a file */ +#define X_BUF 2 /* input is a buffer */ + +struct context cx; /* the current context */ diff --git a/usr.bin/window/defs.h b/usr.bin/window/defs.h new file mode 100644 index 0000000..59eb729 --- /dev/null +++ b/usr.bin/window/defs.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)defs.h 8.1 (Berkeley) 6/6/93 + */ + +#include "ww.h" +#include + +#define NWINDOW 9 + +struct timeval starttime; + +struct ww *window[NWINDOW]; /* the windows */ +struct ww *selwin; /* the selected window */ +struct ww *lastselwin; /* the last selected window */ +struct ww *cmdwin; /* the command window */ +struct ww *framewin; /* the window for framing */ +struct ww *boxwin; /* the window for the box */ +struct ww *fgwin; /* the last foreground window */ + +#define isfg(w) ((w)->ww_order <= fgwin->ww_order) + +char *default_shell[128]; /* default shell argv */ +char *default_shellfile; /* default shell program */ +int default_nline; /* default buffer size for new windows */ +int default_smooth; /* default "smooth" parameter */ +char escapec; /* the escape character */ + + /* flags */ +char quit; /* quit command issued */ +char terse; /* terse mode */ +char debug; /* debug mode */ +char incmd; /* in command mode */ + +struct ww *getwin(); +struct ww *openwin(); +struct ww *vtowin(); +struct ww *openiwin(); diff --git a/usr.bin/window/error.c b/usr.bin/window/error.c new file mode 100644 index 0000000..63e0614 --- /dev/null +++ b/usr.bin/window/error.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)error.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "value.h" +#include "context.h" +#include "char.h" + +#define ERRLINES 10 /* number of lines for errwin */ + +/*VARARGS1*/ +error(fmt, a, b, c, d, e, f, g, h) +char *fmt; +{ + register struct context *x; + register struct ww *w; + + for (x = &cx; x != 0 && x->x_type != X_FILE; x = x->x_link) + ; + if (x == 0) { + if (terse) + wwbell(); + else { + wwprintf(cmdwin, fmt, a, b, c, d, e, f, g, h); + wwputs(" ", cmdwin); + } + return; + } + if (x->x_noerr) + return; + if ((w = x->x_errwin) == 0) { + char buf[512]; + + (void) sprintf(buf, "Errors from %s", x->x_filename); + if ((w = x->x_errwin = openiwin(ERRLINES, buf)) == 0) { + wwputs("Can't open error window. ", cmdwin); + x->x_noerr = 1; + return; + } + } + if (more(w, 0) == 2) { + x->x_noerr = 1; + return; + } + wwprintf(w, "line %d: ", x->x_lineno); + wwprintf(w, fmt, a, b, c, d, e, f, g, h); + wwputc('\n', w); +} + +err_end() +{ + if (cx.x_type == X_FILE && cx.x_errwin != 0) { + if (!cx.x_noerr) + waitnl(cx.x_errwin); + closeiwin(cx.x_errwin); + cx.x_errwin = 0; + } +} diff --git a/usr.bin/window/lcmd.c b/usr.bin/window/lcmd.c new file mode 100644 index 0000000..3938aa7 --- /dev/null +++ b/usr.bin/window/lcmd.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lcmd.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "value.h" +#include "lcmd.h" + +int l_alias(); +int l_close(); +int l_cursormodes(); +int l_debug(); +int l_def_nline(); +int l_def_shell(); +int l_def_smooth(); +int l_echo(); +int l_escape(); +int l_foreground(); +int l_iostat(); +int l_label(); +int l_list(); +int l_select(); +int l_smooth(); +int l_source(); +int l_terse(); +int l_time(); +int l_unalias(); +int l_unset(); +int l_variable(); +int l_window(); +int l_write(); + +extern struct lcmd_arg arg_alias[]; +extern struct lcmd_arg arg_cursormodes[]; +extern struct lcmd_arg arg_debug[]; +extern struct lcmd_arg arg_echo[]; +extern struct lcmd_arg arg_escape[]; +extern struct lcmd_arg arg_foreground[]; +extern struct lcmd_arg arg_label[]; +extern struct lcmd_arg arg_def_nline[]; +extern struct lcmd_arg arg_def_shell[]; +extern struct lcmd_arg arg_def_smooth[]; +extern struct lcmd_arg arg_close[]; +extern struct lcmd_arg arg_select[]; +extern struct lcmd_arg arg_smooth[]; +extern struct lcmd_arg arg_source[]; +extern struct lcmd_arg arg_terse[]; +extern struct lcmd_arg arg_time[]; +extern struct lcmd_arg arg_unalias[]; +extern struct lcmd_arg arg_unset[]; +extern struct lcmd_arg arg_window[]; +extern struct lcmd_arg arg_write[]; +struct lcmd_arg arg_null[1] = { { 0 } }; + +struct lcmd_tab lcmd_tab[] = { + "alias", 1, l_alias, arg_alias, + "close", 2, l_close, arg_close, + "cursormodes", 2, l_cursormodes, arg_cursormodes, + "debug", 1, l_debug, arg_debug, + "default_nlines", 9, l_def_nline, arg_def_nline, + "default_shell", 10, l_def_shell, arg_def_shell, + "default_smooth", 10, l_def_smooth, arg_def_smooth, + "echo", 2, l_echo, arg_echo, + "escape", 2, l_escape, arg_escape, + "foreground", 1, l_foreground, arg_foreground, + "iostat", 1, l_iostat, arg_null, + "label", 2, l_label, arg_label, + "list", 2, l_list, arg_null, + "nlines", 1, l_def_nline, arg_def_nline, + "select", 2, l_select, arg_select, + "shell", 2, l_def_shell, arg_def_shell, + "smooth", 2, l_smooth, arg_smooth, + "source", 2, l_source, arg_source, + "terse", 2, l_terse, arg_terse, + "time", 2, l_time, arg_time, + "unalias", 3, l_unalias, arg_unalias, + "unset", 3, l_unset, arg_unset, + "variable", 1, l_variable, arg_null, + "window", 2, l_window, arg_window, + "write", 2, l_write, arg_write, + 0 +}; + +struct lcmd_tab * +lcmd_lookup(name) +char *name; +{ + register struct lcmd_tab *p; + + for (p = lcmd_tab; p->lc_name != 0; p++) + if (str_match(name, p->lc_name, p->lc_minlen)) + return p; + return 0; +} + +dosource(filename) +char *filename; +{ + if (cx_beginfile(filename) < 0) + return -1; + p_start(); + err_end(); + cx_end(); + return 0; +} + +dolongcmd(buffer, arg, narg) +char *buffer; +struct value *arg; +int narg; +{ + if (cx_beginbuf(buffer, arg, narg) < 0) + return -1; + p_start(); + err_end(); + cx_end(); + return 0; +} diff --git a/usr.bin/window/lcmd.h b/usr.bin/window/lcmd.h new file mode 100644 index 0000000..b3d1394 --- /dev/null +++ b/usr.bin/window/lcmd.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)lcmd.h 8.1 (Berkeley) 6/6/93 + */ + +#define LCMD_NARG 20 /* maximum number of arguments */ + +struct lcmd_tab { + char *lc_name; + int lc_minlen; + int (*lc_func)(); + struct lcmd_arg *lc_arg; +}; + +struct lcmd_arg { + char *arg_name; + int arg_minlen; + int arg_flags; +}; + + /* arg_flags bits */ +#define ARG_TYPE 0x0f /* type of arg */ +#define ARG_ANY 0x00 /* any type */ +#define ARG_NUM 0x01 /* must be a number */ +#define ARG_STR 0x02 /* must be a string */ +#define ARG_LIST 0x10 /* this arg can be a list */ + +struct lcmd_tab *lcmd_lookup(); diff --git a/usr.bin/window/lcmd1.c b/usr.bin/window/lcmd1.c new file mode 100644 index 0000000..ff96cac --- /dev/null +++ b/usr.bin/window/lcmd1.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lcmd1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "string.h" +#include "value.h" +#include "lcmd.h" +#include "var.h" + +struct lcmd_arg arg_window[] = { + { "row", 1, ARG_NUM }, + { "column", 1, ARG_NUM }, + { "nrows", 2, ARG_NUM }, + { "ncols", 2, ARG_NUM }, + { "nlines", 2, ARG_NUM }, + { "label", 1, ARG_STR }, + { "pty", 1, ARG_ANY }, + { "frame", 1, ARG_ANY }, + { "mapnl", 1, ARG_ANY }, + { "keepopen", 1, ARG_ANY }, + { "smooth", 1, ARG_ANY }, + { "shell", 1, ARG_STR|ARG_LIST }, + 0 +}; + +l_window(v, a) +struct value *v; +register struct value *a; +{ + struct ww *w; + int col, row, ncol, nrow, id, nline; + char *label; + char haspty, hasframe, mapnl, keepopen, smooth; + char *shf, **sh; + char *argv[sizeof default_shell / sizeof *default_shell]; + register char **pp; + + if ((id = findid()) < 0) + return; + row = a->v_type == V_ERR ? 1 : a->v_num; + a++; + col = a->v_type == V_ERR ? 0 : a->v_num; + a++; + nrow = a->v_type == V_ERR ? wwnrow - row : a->v_num; + a++; + ncol = a->v_type == V_ERR ? wwncol - col : a->v_num; + a++; + nline = a->v_type == V_ERR ? default_nline : a->v_num; + a++; + label = a->v_type == V_ERR ? 0 : a->v_str; + if ((haspty = vtobool(++a, 1, -1)) < 0) + return; + if ((hasframe = vtobool(++a, 1, -1)) < 0) + return; + if ((mapnl = vtobool(++a, !haspty, -1)) < 0) + return; + if ((keepopen = vtobool(++a, 0, -1)) < 0) + return; + if ((smooth = vtobool(++a, default_smooth, -1)) < 0) + return; + if ((++a)->v_type != V_ERR) { + for (pp = argv; a->v_type != V_ERR && + pp < &argv[sizeof argv/sizeof *argv-1]; pp++, a++) + *pp = a->v_str; + *pp = 0; + shf = *(sh = argv); + if (*sh = rindex(shf, '/')) + (*sh)++; + else + *sh = shf; + } else { + sh = default_shell; + shf = default_shellfile; + } + if ((w = openwin(id, row, col, nrow, ncol, nline, label, haspty, + hasframe, shf, sh)) == 0) + return; + w->ww_mapnl = mapnl; + w->ww_keepopen = keepopen; + w->ww_noupdate = !smooth; + v->v_type = V_NUM; + v->v_num = id + 1; +} + +struct lcmd_arg arg_def_nline[] = { + { "nlines", 1, ARG_NUM }, + 0 +}; + +l_def_nline(v, a) +register struct value *v, *a; +{ + v->v_num = default_nline; + v->v_type = V_NUM; + if (a->v_type != V_ERR) + default_nline = a->v_num; +} + +struct lcmd_arg arg_smooth[] = { + { "window", 1, ARG_NUM }, + { "flag", 1, ARG_ANY }, + 0 +}; + +l_smooth(v, a) +register struct value *v, *a; +{ + struct ww *w; + + v->v_type = V_NUM; + v->v_num = 0; + if ((w = vtowin(a++, selwin)) == 0) + return; + v->v_num = !w->ww_noupdate; + w->ww_noupdate = !vtobool(a, v->v_num, v->v_num); +} + +struct lcmd_arg arg_def_smooth[] = { + { "flag", 1, ARG_ANY }, + 0 +}; + +l_def_smooth(v, a) +register struct value *v, *a; +{ + v->v_type = V_NUM; + v->v_num = default_smooth; + default_smooth = vtobool(a, v->v_num, v->v_num); +} + +struct lcmd_arg arg_select[] = { + { "window", 1, ARG_NUM }, + 0 +}; + +l_select(v, a) +register struct value *v, *a; +{ + struct ww *w; + + v->v_type = V_NUM; + v->v_num = selwin ? selwin->ww_id + 1 : -1; + if (a->v_type == V_ERR) + return; + if ((w = vtowin(a, (struct ww *)0)) == 0) + return; + setselwin(w); +} + +struct lcmd_arg arg_debug[] = { + { "flag", 1, ARG_ANY }, + 0 +}; + +l_debug(v, a) +register struct value *v, *a; +{ + v->v_type = V_NUM; + v->v_num = debug; + debug = vtobool(a, debug, debug); +} + +struct lcmd_arg arg_escape[] = { + { "escapec", 1, ARG_STR }, + 0 +}; + +l_escape(v, a) +register struct value *v, *a; +{ + char buf[2]; + + buf[0] = escapec; + buf[1] = 0; + if ((v->v_str = str_cpy(buf)) == 0) { + error("Out of memory."); + return; + } + v->v_type = V_STR; + if (a->v_type != V_ERR) + setescape(a->v_str); +} + +struct lcmd_arg arg_label[] = { + { "window", 1, ARG_NUM }, + { "label", 1, ARG_STR }, + 0 +}; + +/*ARGSUSED*/ +l_label(v, a) +struct value *v; +register struct value *a; +{ + struct ww *w; + + if ((w = vtowin(a, selwin)) == 0) + return; + if ((++a)->v_type != V_ERR && setlabel(w, a->v_str) < 0) + error("Out of memory."); + reframe(); +} + +struct lcmd_arg arg_foreground[] = { + { "window", 1, ARG_NUM }, + { "flag", 1, ARG_ANY }, + 0 +}; + +l_foreground(v, a) +register struct value *v, *a; +{ + struct ww *w; + char flag; + + if ((w = vtowin(a, selwin)) == 0) + return; + v->v_type = V_NUM; + v->v_num = isfg(w); + flag = vtobool(++a, v->v_num, v->v_num); + if (flag == v->v_num) + return; + deletewin(w); + addwin(w, flag); + reframe(); +} + +struct lcmd_arg arg_terse[] = { + { "flag", 1, ARG_ANY }, + 0 +}; + +l_terse(v, a) +register struct value *v, *a; +{ + v->v_type = V_NUM; + v->v_num = terse; + setterse(vtobool(a, terse, terse)); +} + +struct lcmd_arg arg_source[] = { + { "filename", 1, ARG_STR }, + 0 +}; + +l_source(v, a) +register struct value *v, *a; +{ + v->v_type = V_NUM; + if (a->v_type != V_ERR && dosource(a->v_str) < 0) { + error("Can't open %s.", a->v_str); + v->v_num = -1; + } else + v->v_num = 0; +} + +struct lcmd_arg arg_write[] = { + { "window", 1, ARG_NUM }, + { "", 0, ARG_ANY|ARG_LIST }, + 0 +}; + +/*ARGSUSED*/ +l_write(v, a) +struct value *v; +register struct value *a; +{ + char buf[20]; + struct ww *w; + + if ((w = vtowin(a++, selwin)) == 0) + return; + while (a->v_type != V_ERR) { + if (a->v_type == V_NUM) { + (void) sprintf(buf, "%d", a->v_num); + (void) write(w->ww_pty, buf, strlen(buf)); + } else + (void) write(w->ww_pty, a->v_str, strlen(a->v_str)); + if ((++a)->v_type != V_ERR) + (void) write(w->ww_pty, " ", 1); + } +} + +struct lcmd_arg arg_close[] = { + { "window", 1, ARG_ANY|ARG_LIST }, + 0 +}; + +/*ARGSUSED*/ +l_close(v, a) +struct value *v; +register struct value *a; +{ + struct ww *w; + + if (a->v_type == V_STR && str_match(a->v_str, "all", 3)) + closewin((struct ww *)0); + else + for (; a->v_type != V_ERR; a++) + if ((w = vtowin(a, (struct ww *)0)) != 0) + closewin(w); +} + +struct lcmd_arg arg_cursormodes[] = { + { "modes", 1, ARG_NUM }, + 0 +}; + +l_cursormodes(v, a) +register struct value *v, *a; +{ + + v->v_type = V_NUM; + v->v_num = wwcursormodes; + if (a->v_type != V_ERR) + wwsetcursormodes(a->v_num); +} + +struct lcmd_arg arg_unset[] = { + { "variable", 1, ARG_ANY }, + 0 +}; + +l_unset(v, a) +register struct value *v, *a; +{ + v->v_type = V_NUM; + switch (a->v_type) { + case V_ERR: + v->v_num = -1; + return; + case V_NUM: + if ((a->v_str = str_itoa(a->v_num)) == 0) { + error("Out of memory."); + v->v_num = -1; + return; + } + a->v_type = V_STR; + break; + } + v->v_num = var_unset(a->v_str); +} + +struct ww * +vtowin(v, w) +register struct value *v; +struct ww *w; +{ + switch (v->v_type) { + case V_ERR: + if (w != 0) + return w; + error("No window specified."); + return 0; + case V_STR: + error("%s: No such window.", v->v_str); + return 0; + } + if (v->v_num < 1 || v->v_num > NWINDOW + || (w = window[v->v_num - 1]) == 0) { + error("%d: No such window.", v->v_num); + return 0; + } + return w; +} + +vtobool(v, def, err) +register struct value *v; +char def, err; +{ + switch (v->v_type) { + case V_NUM: + return v->v_num != 0; + case V_STR: + if (str_match(v->v_str, "true", 1) + || str_match(v->v_str, "on", 2) + || str_match(v->v_str, "yes", 1)) + return 1; + else if (str_match(v->v_str, "false", 1) + || str_match(v->v_str, "off", 2) + || str_match(v->v_str, "no", 1)) + return 0; + else { + error("%s: Illegal boolean value.", v->v_str); + return err; + } + /*NOTREACHED*/ + case V_ERR: + return def; + } + /*NOTREACHED*/ +} diff --git a/usr.bin/window/lcmd2.c b/usr.bin/window/lcmd2.c new file mode 100644 index 0000000..599cc98 --- /dev/null +++ b/usr.bin/window/lcmd2.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lcmd2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "string.h" +#include "value.h" +#include "var.h" +#include "lcmd.h" +#include "alias.h" +#include +#include + +/*ARGSUSED*/ +l_iostat(v, a) +struct value *v, *a; +{ + register struct ww *w; + + if ((w = openiwin(16, "IO Statistics")) == 0) { + error("Can't open statistics window: %s.", wwerror()); + return; + } + wwprintf(w, "ttflush\twrite\terror\tzero\tchar\n"); + wwprintf(w, "%d\t%d\t%d\t%d\t%d\n", + wwnflush, wwnwr, wwnwre, wwnwrz, wwnwrc); + wwprintf(w, "token\tuse\tbad\tsaving\ttotal\tbaud\n"); + wwprintf(w, "%d\t%d\t%d\t%d\t%d\t%d/%d (%.1f/%.1f)\n", + wwntokdef, wwntokuse, wwntokbad, wwntoksave, wwntokc, + wwntokc - wwntoksave ? + (int) ((float) wwbaud * wwntokc / + (wwntokc - wwntoksave)) : + wwbaud, + wwnwrc ? (int) ((float) wwbaud * (wwnwrc + wwntoksave) / + wwnwrc) : + wwbaud, + wwntokc - wwntoksave ? + (float) wwntokc / (wwntokc - wwntoksave) : 1.0, + wwnwrc ? (float) (wwnwrc + wwntoksave) / wwnwrc : 1.0); + wwprintf(w, "wwwrite\tattempt\tchar\n"); + wwprintf(w, "%d\t%d\t%d\n", + wwnwwr, wwnwwra, wwnwwrc); + wwprintf(w, "wwupdat\tline\tmiss\tscan\tclreol\tclreos\tmiss\tline\n"); + wwprintf(w, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", + wwnupdate, wwnupdline, wwnupdmiss, wwnupdscan, wwnupdclreol, + wwnupdclreos, wwnupdclreosmiss, wwnupdclreosline); + wwprintf(w, "select\terror\tzero\n"); + wwprintf(w, "%d\t%d\t%d\n", + wwnselect, wwnselecte, wwnselectz); + wwprintf(w, "read\terror\tzero\tchar\tack\tnack\tstat\terrorc\n"); + wwprintf(w, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", + wwnread, wwnreade, wwnreadz, wwnreadc, wwnreadack, wwnreadnack, + wwnreadstat, wwnreadec); + wwprintf(w, "ptyread\terror\tzero\tcontrol\tdata\tchar\n"); + wwprintf(w, "%d\t%d\t%d\t%d\t%d\t%d\n", + wwnwread, wwnwreade, wwnwreadz, + wwnwreadp, wwnwreadd, wwnwreadc); + waitnl(w); + closeiwin(w); +} + +struct lcmd_arg arg_time[] = { + { "who", 1, ARG_STR }, + 0 +}; + +/*ARGSUSED*/ +l_time(v, a) +struct value *v; +register struct value *a; +{ + register struct ww *w; + struct rusage rusage; + struct timeval timeval; + char *strtime(); + + if ((w = openiwin(8, "Timing and Resource Usage")) == 0) { + error("Can't open time window: %s.", wwerror()); + return; + } + + (void) gettimeofday(&timeval, (struct timezone *)0); + timeval.tv_sec -= starttime.tv_sec; + if ((timeval.tv_usec -= starttime.tv_usec) < 0) { + timeval.tv_sec--; + timeval.tv_usec += 1000000; + } + (void) getrusage(a->v_type == V_STR + && str_match(a->v_str, "children", 1) + ? RUSAGE_CHILDREN : RUSAGE_SELF, &rusage); + + wwprintf(w, "%-15s %-15s %-15s\n", + "time", "utime", "stime"); + wwprintf(w, "%-15s ", strtime(&timeval)); + wwprintf(w, "%-15s ", strtime(&rusage.ru_utime)); + wwprintf(w, "%-15s\n", strtime(&rusage.ru_stime)); + wwprintf(w, "%-15s %-15s %-15s %-15s\n", + "maxrss", "ixrss", "idrss", "isrss"); + wwprintf(w, "%-15ld %-15ld %-15ld %-15ld\n", + rusage.ru_maxrss, rusage.ru_ixrss, + rusage.ru_idrss, rusage.ru_isrss); + wwprintf(w, "%-7s %-7s %-7s %-7s %-7s %-7s %-7s %-7s %-7s %-7s\n", + "minflt", "majflt", "nswap", "inblk", "oublk", + "msgsnd", "msgrcv", "nsigs", "nvcsw", "nivcsw"); + wwprintf(w, "%-7ld %-7ld %-7ld %-7ld %-7ld %-7ld %-7ld %-7ld %-7ld %-7ld\n", + rusage.ru_minflt, rusage.ru_majflt, rusage.ru_nswap, + rusage.ru_inblock, rusage.ru_oublock, + rusage.ru_msgsnd, rusage.ru_msgrcv, rusage.ru_nsignals, + rusage.ru_nvcsw, rusage.ru_nivcsw); + + waitnl(w); + closeiwin(w); +} + +char * +strtime(t) +register struct timeval *t; +{ + char fill = 0; + static char buf[20]; + register char *p = buf; + + if (t->tv_sec > 60*60) { + (void) sprintf(p, "%ld:", t->tv_sec / (60*60)); + while (*p++) + ; + p--; + t->tv_sec %= 60*60; + fill++; + } + if (t->tv_sec > 60) { + (void) sprintf(p, fill ? "%02ld:" : "%ld:", t->tv_sec / 60); + while (*p++) + ; + p--; + t->tv_sec %= 60; + fill++; + } + (void) sprintf(p, fill ? "%02ld.%02d" : "%ld.%02ld", + t->tv_sec, t->tv_usec / 10000); + return buf; +} + +/*ARGSUSED*/ +l_list(v, a) +struct value *v, *a; +{ + register struct ww *w, *wp; + register i; + int n; + + for (n = 0, i = 0; i < NWINDOW; i++) + if (window[i] != 0) + n++; + if (n == 0) { + error("No windows."); + return; + } + if ((w = openiwin(n + 2, "Windows")) == 0) { + error("Can't open listing window: %s.", wwerror()); + return; + } + for (i = 0; i < NWINDOW; i++) { + if ((wp = window[i]) == 0) + continue; + wwprintf(w, "%c %c %-13s %-.*s\n", + wp == selwin ? '+' : (wp == lastselwin ? '-' : ' '), + i + '1', + wp->ww_state == WWS_HASPROC ? "" : "(No process)", + wwncol - 20, + wp->ww_label ? wp->ww_label : "(No label)"); + } + waitnl(w); + closeiwin(w); +} + +/*ARGSUSED*/ +l_variable(v, a) +struct value *v, *a; +{ + register struct ww *w; + int printvar(); + + if ((w = openiwin(wwnrow - 3, "Variables")) == 0) { + error("Can't open variable window: %s.", wwerror()); + return; + } + if (var_walk(printvar, (int)w) >= 0) + waitnl(w); + closeiwin(w); +} + +printvar(w, r) +register struct ww *w; +register struct var *r; +{ + if (more(w, 0) == 2) + return -1; + wwprintf(w, "%16s ", r->r_name); + switch (r->r_val.v_type) { + case V_STR: + wwprintf(w, "%s\n", r->r_val.v_str); + break; + case V_NUM: + wwprintf(w, "%d\n", r->r_val.v_num); + break; + case V_ERR: + wwprintf(w, "ERROR\n"); + break; + } + return 0; +} + +struct lcmd_arg arg_def_shell[] = { + { "", 0, ARG_ANY|ARG_LIST }, + 0 +}; + +l_def_shell(v, a) + struct value *v, *a; +{ + register char **pp; + register struct value *vp; + + if (a->v_type == V_ERR) { + if ((v->v_str = str_cpy(default_shellfile)) != 0) + v->v_type = V_STR; + return; + } + if (v->v_str = default_shellfile) { + v->v_type = V_STR; + for (pp = default_shell + 1; *pp; pp++) { + str_free(*pp); + *pp = 0; + } + } + for (pp = default_shell, vp = a; + vp->v_type != V_ERR && + pp < &default_shell[sizeof default_shell/sizeof *default_shell-1]; + pp++, vp++) + if ((*pp = vp->v_type == V_STR ? + str_cpy(vp->v_str) : str_itoa(vp->v_num)) == 0) { + /* just leave default_shell[] the way it is */ + p_memerror(); + break; + } + if (default_shellfile = *default_shell) + if (*default_shell = rindex(default_shellfile, '/')) + (*default_shell)++; + else + *default_shell = default_shellfile; +} + +struct lcmd_arg arg_alias[] = { + { "", 0, ARG_STR }, + { "", 0, ARG_STR|ARG_LIST }, + 0 +}; + +l_alias(v, a) + struct value *v, *a; +{ + if (a->v_type == V_ERR) { + register struct ww *w; + int printalias(); + + if ((w = openiwin(wwnrow - 3, "Aliases")) == 0) { + error("Can't open alias window: %s.", wwerror()); + return; + } + if (alias_walk(printalias, (int)w) >= 0) + waitnl(w); + closeiwin(w); + } else { + register struct alias *ap = 0; + + if (ap = alias_lookup(a->v_str)) { + if ((v->v_str = str_cpy(ap->a_buf)) == 0) { + p_memerror(); + return; + } + v->v_type = V_STR; + } + if (a[1].v_type == V_STR) { + register struct value *vp; + register char *p, *q; + char *str; + register n; + + for (n = 0, vp = a + 1; vp->v_type != V_ERR; vp++, n++) + for (p = vp->v_str; *p; p++, n++) + ; + if ((str = str_alloc(n)) == 0) { + p_memerror(); + return; + } + for (q = str, vp = a + 1; vp->v_type != V_ERR; + vp++, q[-1] = ' ') + for (p = vp->v_str; *q++ = *p++;) + ; + q[-1] = 0; + if ((ap = alias_set(a[0].v_str, (char *)0)) == 0) { + p_memerror(); + str_free(str); + return; + } + ap->a_buf = str; + } + } +} + +printalias(w, a) +register struct ww *w; +register struct alias *a; +{ + if (more(w, 0) == 2) + return -1; + wwprintf(w, "%16s %s\n", a->a_name, a->a_buf); + return 0; +} + +struct lcmd_arg arg_unalias[] = { + { "alias", 1, ARG_STR }, + 0 +}; + +l_unalias(v, a) +struct value *v, *a; +{ + if (a->v_type == ARG_STR) + v->v_num = alias_unset(a->v_str); + v->v_type = V_NUM; +} + +struct lcmd_arg arg_echo[] = { + { "window", 1, ARG_NUM }, + { "", 0, ARG_ANY|ARG_LIST }, + 0 +}; + +/*ARGSUSED*/ +l_echo(v, a) +struct value *v; +register struct value *a; +{ + char buf[20]; + struct ww *w; + + if ((w = vtowin(a++, selwin)) == 0) + return; + while (a->v_type != V_ERR) { + if (a->v_type == V_NUM) { + (void) sprintf(buf, "%d", a->v_num); + (void) wwwrite(w, buf, strlen(buf)); + } else + (void) wwwrite(w, a->v_str, strlen(a->v_str)); + if ((++a)->v_type != V_ERR) + (void) wwwrite(w, " ", 1); + } + (void) wwwrite(w, "\r\n", 2); +} diff --git a/usr.bin/window/local.h b/usr.bin/window/local.h new file mode 100644 index 0000000..90378d8 --- /dev/null +++ b/usr.bin/window/local.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)local.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Things of local interest. + */ + +#define RUNCOM ".windowrc" +#define ESCAPEC ctrl('p') +#define NLINE 48 /* default text buffer size */ + +#ifdef TERMINFO +#define _PATH_CAPTOINFO "/usr/5bin/captoinfo" +#define _PATH_TIC "/usr/5bin/tic" +#define _PATH_RM "/bin/rm" +#endif diff --git a/usr.bin/window/main.c b/usr.bin/window/main.c new file mode 100644 index 0000000..15de840 --- /dev/null +++ b/usr.bin/window/main.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1983, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include "defs.h" +#include +#include +#include "string.h" +#include "char.h" +#include "local.h" + +#define next(a) (*++*(a) ? *(a) : (*++(a) ? *(a) : (char *)usage())) + +/*ARGSUSED*/ +main(argc, argv) +char **argv; +{ + register char *p; + char fflag = 0; + char dflag = 0; + char xflag = 0; + char *cmd = 0; + char tflag = 0; + + escapec = ESCAPEC; + if (p = rindex(*argv, '/')) + p++; + else + p = *argv; + debug = strcmp(p, "a.out") == 0; + while (*++argv) { + if (**argv == '-') { + switch (*++*argv) { + case 'f': + fflag++; + break; + case 'c': + if (cmd != 0) { + (void) fprintf(stderr, + "Only one -c allowed.\n"); + (void) usage(); + } + cmd = next(argv); + break; + case 'e': + setescape(next(argv)); + break; + case 't': + tflag++; + break; + case 'd': + dflag++; + break; + case 'D': + debug = !debug; + break; + case 'x': + xflag++; + break; + default: + (void) usage(); + } + } else + (void) usage(); + } + if ((p = getenv("SHELL")) == 0) + p = _PATH_BSHELL; + if ((default_shellfile = str_cpy(p)) == 0) { + (void) fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if (p = rindex(default_shellfile, '/')) + p++; + else + p = default_shellfile; + default_shell[0] = p; + default_shell[1] = 0; + default_nline = NLINE; + default_smooth = 1; + (void) gettimeofday(&starttime, (struct timezone *)0); + if (wwinit() < 0) { + (void) fprintf(stderr, "%s.\n", wwerror()); + exit(1); + } + +#ifdef OLD_TTY + if (debug) + wwnewtty.ww_tchars.t_quitc = wwoldtty.ww_tchars.t_quitc; + if (xflag) { + wwnewtty.ww_tchars.t_stopc = wwoldtty.ww_tchars.t_stopc; + wwnewtty.ww_tchars.t_startc = wwoldtty.ww_tchars.t_startc; + } +#else + if (debug) { + wwnewtty.ww_termios.c_cc[VQUIT] = + wwoldtty.ww_termios.c_cc[VQUIT]; + wwnewtty.ww_termios.c_lflag |= ISIG; + } + if (xflag) { + wwnewtty.ww_termios.c_cc[VSTOP] = + wwoldtty.ww_termios.c_cc[VSTOP]; + wwnewtty.ww_termios.c_cc[VSTART] = + wwoldtty.ww_termios.c_cc[VSTART]; + wwnewtty.ww_termios.c_iflag |= IXON; + } +#endif + if (debug || xflag) + (void) wwsettty(0, &wwnewtty); + + if ((cmdwin = wwopen(wwbaud > 2400 ? WWO_REVERSE : 0, 1, wwncol, + 0, 0, 0)) == 0) { + wwflush(); + (void) fprintf(stderr, "%s.\r\n", wwerror()); + goto bad; + } + cmdwin->ww_mapnl = 1; + cmdwin->ww_nointr = 1; + cmdwin->ww_noupdate = 1; + cmdwin->ww_unctrl = 1; + if ((framewin = wwopen(WWO_GLASS|WWO_FRAME, wwnrow, wwncol, 0, 0, 0)) + == 0) { + wwflush(); + (void) fprintf(stderr, "%s.\r\n", wwerror()); + goto bad; + } + wwadd(framewin, &wwhead); + if ((boxwin = wwopen(WWO_GLASS, wwnrow, wwncol, 0, 0, 0)) == 0) { + wwflush(); + (void) fprintf(stderr, "%s.\r\n", wwerror()); + goto bad; + } + fgwin = framewin; + + wwupdate(); + wwflush(); + setvars(); + + setterse(tflag); + setcmd(1); + if (cmd != 0) + (void) dolongcmd(cmd, (struct value *)0, 0); + if (!fflag) + if (dflag || doconfig() < 0) + dodefault(); + if (selwin != 0) + setcmd(0); + + mloop(); + +bad: + wwend(1); + return 0; +} + +usage() +{ + (void) fprintf(stderr, "Usage: window [-e escape-char] [-c command] [-t] [-f] [-d]\n"); + exit(1); + return 0; /* for lint */ +} diff --git a/usr.bin/window/mloop.c b/usr.bin/window/mloop.c new file mode 100644 index 0000000..68584e7 --- /dev/null +++ b/usr.bin/window/mloop.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)mloop.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include "defs.h" + +mloop() +{ + while (!quit) { + if (incmd) { + docmd(); + } else if (wwcurwin->ww_state != WWS_HASPROC) { + if (!wwcurwin->ww_keepopen) + closewin(wwcurwin); + setcmd(1); + if (wwpeekc() == escapec) + (void) wwgetc(); + error("Process died."); + } else { + register struct ww *w = wwcurwin; + register char *p; + register n; + + if (wwibp >= wwibq) + wwiomux(); + for (p = wwibp; p < wwibq && wwmaskc(*p) != escapec; + p++) + ; + if ((n = p - wwibp) > 0) { + if (!w->ww_ispty && w->ww_stopped) + startwin(w); +#if defined(sun) && !defined(BSD) + /* workaround for SunOS pty bug */ + while (--n >= 0) + (void) write(w->ww_pty, wwibp++, 1); +#else + (void) write(w->ww_pty, wwibp, n); + wwibp = p; +#endif + } + if (wwpeekc() == escapec) { + (void) wwgetc(); + setcmd(1); + } + } + } +} diff --git a/usr.bin/window/parser.h b/usr.bin/window/parser.h new file mode 100644 index 0000000..747ae4b --- /dev/null +++ b/usr.bin/window/parser.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)parser.h 8.1 (Berkeley) 6/6/93 + */ + +#include "value.h" +#include "context.h" +#include "token.h" +#include "string.h" + +#define p_erred() (cx.x_erred) +#define p_synerred() (cx.x_synerred) +#define p_clearerr() (cx.x_erred = cx.x_synerred = 0) +#define p_abort() (cx.x_abort) diff --git a/usr.bin/window/parser1.c b/usr.bin/window/parser1.c new file mode 100644 index 0000000..9cc9790 --- /dev/null +++ b/usr.bin/window/parser1.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parser1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "parser.h" + +p_start() +{ + char flag = 1; + + (void) s_gettok(); + for (;;) { + p_statementlist(flag); + if (token == T_EOF || p_abort()) + break; + flag = 0; + p_synerror(); + while (token != T_EOL && token != T_EOF) { + if (token == T_STR) + str_free(token_str); + (void) s_gettok(); + } + if (token == T_EOL) + (void) s_gettok(); + p_clearerr(); + } +} + +p_statementlist(flag) +char flag; +{ + for (; p_statement(flag) >= 0; p_clearerr()) + ; +} + +p_statement(flag) +char flag; +{ + switch (token) { + case T_EOL: + (void) s_gettok(); + return 0; + case T_IF: + return p_if(flag); + default: + return p_expression(flag); + } +} + +p_if(flag) +char flag; +{ + struct value t; + char true = 0; + +top: + (void) s_gettok(); + + if (p_expr(&t, flag) < 0) { + p_synerror(); + return -1; + } + switch (t.v_type) { + case V_NUM: + true = !true && t.v_num != 0; + break; + case V_STR: + p_error("if: Numeric value required."); + str_free(t.v_str); + case V_ERR: + flag = 0; + break; + } + + if (token != T_THEN) { + p_synerror(); + return -1; + } + + (void) s_gettok(); + p_statementlist(flag && true); + if (p_erred()) + return -1; + + if (token == T_ELSIF) + goto top; + + if (token == T_ELSE) { + (void) s_gettok(); + p_statementlist(flag && !true); + if (p_erred()) + return -1; + } + + if (token == T_ENDIF) { + (void) s_gettok(); + return 0; + } + + p_synerror(); + return -1; +} + +p_expression(flag) +char flag; +{ + struct value t; + char *cmd; + int p_function(), p_assign(); + + switch (token) { + case T_NUM: + t.v_type = V_NUM; + t.v_num = token_num; + (void) s_gettok(); + break; + case T_STR: + t.v_type = V_STR; + t.v_str = token_str; + (void) s_gettok(); + break; + default: + if (p_expr(&t, flag) < 0) + return -1; + if (token == T_EOF) { + val_free(t); + return 0; + } + } + if (token != T_ASSIGN && p_convstr(&t) < 0) + return -1; + cmd = t.v_type == V_STR ? t.v_str : 0; + if ((*(token == T_ASSIGN ? p_assign : p_function))(cmd, &t, flag) < 0) { + if (cmd) + str_free(cmd); + return -1; + } + if (cmd) + str_free(cmd); + val_free(t); + if (token == T_EOL) + (void) s_gettok(); + else if (token != T_EOF) { + p_synerror(); + return -1; + } + return 0; +} + +p_convstr(v) +register struct value *v; +{ + if (v->v_type != V_NUM) + return 0; + if ((v->v_str = str_itoa(v->v_num)) == 0) { + p_memerror(); + v->v_type = V_ERR; + return -1; + } + v->v_type = V_STR; + return 0; +} + +p_synerror() +{ + if (!cx.x_synerred) { + cx.x_synerred = cx.x_erred = 1; + error("Syntax error."); + } +} + +/*VARARGS1*/ +p_error(msg, a, b, c) +char *msg; +{ + if (!cx.x_erred) { + cx.x_erred = 1; + error(msg, a, b, c); + } +} + +p_memerror() +{ + cx.x_erred = cx.x_abort = 1; + error("Out of memory."); +} diff --git a/usr.bin/window/parser2.c b/usr.bin/window/parser2.c new file mode 100644 index 0000000..e9b2f55 --- /dev/null +++ b/usr.bin/window/parser2.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parser2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "parser.h" +#include "var.h" +#include "lcmd.h" +#include "alias.h" + +/* + * name == 0 means we don't have a function name but + * want to parse the arguments anyway. flag == 0 in this case. + */ +p_function(name, v, flag) +char *name; +register struct value *v; +{ + struct value t; + register struct lcmd_tab *c = 0; + register struct alias *a = 0; + register struct lcmd_arg *ap; /* this arg */ + struct lcmd_arg *lp = 0; /* list arg */ + register i; + struct value av[LCMD_NARG + 1]; + register struct value *vp; + + if (name != 0) + if (c = lcmd_lookup(name)) + name = c->lc_name; + else if (a = alias_lookup(name)) + name = a->a_name; + else { + p_error("%s: No such command or alias.", name); + flag = 0; + } + + for (vp = av; vp < &av[LCMD_NARG + 1]; vp++) + vp->v_type = V_ERR; + + if (token == T_LP) + (void) s_gettok(); + i = 0; + for (;;) { + ap = 0; + vp = 0; + if (token == T_COMMA) /* null argument */ + t.v_type = V_ERR; + else { + if (p_expr0(&t, flag) < 0) + break; + if (t.v_type == V_ERR) + flag = 0; + } + if (token != T_ASSIGN) { + if (i >= LCMD_NARG || + c != 0 && (ap = lp) == 0 && + (ap = c->lc_arg + i)->arg_name == 0) { + p_error("%s: Too many arguments.", name); + flag = 0; + } else + vp = &av[i++]; + } else { + char *tmp; + if (p_convstr(&t) < 0) + goto abort; + tmp = t.v_type == V_STR ? t.v_str : 0; + (void) s_gettok(); + if (p_expr(&t, flag) < 0) { + if (tmp) + str_free(tmp); + p_synerror(); + goto abort; + } + if (t.v_type == V_ERR) + flag = 0; + if (tmp) { + if (c == 0) { + /* an aliase */ + p_error("%s: Bad alias syntax.", name); + flag = 0; + } else { + for (ap = c->lc_arg, vp = av; + ap != 0 && ap->arg_name != 0 && + (*ap->arg_name == '\0' || + !str_match(tmp, ap->arg_name, + ap->arg_minlen)); + ap++, vp++) + ; + if (ap == 0 || ap->arg_name == 0) { + p_error("%s: Unknown argument \"%s\".", + name, tmp); + flag = 0; + ap = 0; + vp = 0; + } + } + str_free(tmp); + } + } + if (ap != 0) { + if (ap->arg_flags & ARG_LIST) { + i = vp - av + 1; + lp = ap; + } + if (vp->v_type != V_ERR) { + if (*ap->arg_name) + p_error("%s: Argument %d (%s) duplicated.", + name, vp - av + 1, + ap->arg_name); + else + p_error("%s: Argument %d duplicated.", + name, vp - av + 1); + flag = 0; + vp = 0; + } else if (t.v_type == V_ERR) { + /* do nothing */ + } else if ((ap->arg_flags&ARG_TYPE) == ARG_NUM && + t.v_type != V_NUM || + (ap->arg_flags&ARG_TYPE) == ARG_STR && + t.v_type != V_STR) { + if (*ap->arg_name) + p_error("%s: Argument %d (%s) type mismatch.", + name, vp - av + 1, + ap->arg_name); + else + p_error("%s: Argument %d type mismatch.", + name, vp - av + 1); + flag = 0; + vp = 0; + } + } + if (vp != 0) + *vp = t; + else + val_free(t); + if (token == T_COMMA) + (void) s_gettok(); + } + + if (p_erred()) + flag = 0; + if (token == T_RP) + (void) s_gettok(); + else if (token != T_EOL && token != T_EOF) + flag = 0; /* look for legal follow set */ + v->v_type = V_ERR; + if (flag) + if (c != 0) + (*c->lc_func)(v, av); + else + if (a->a_flags & A_INUSE) + p_error("%s: Recursive alias.", a->a_name); + else { + a->a_flags |= A_INUSE; + if (dolongcmd(a->a_buf, av, i) < 0) + p_memerror(); + a->a_flags &= ~A_INUSE; + } + if (p_abort()) { + val_free(*v); + v->v_type = V_ERR; + goto abort; + } + for (vp = av; vp < &av[LCMD_NARG]; vp++) + val_free(*vp); + return 0; +abort: + for (vp = av; vp < &av[LCMD_NARG]; vp++) + val_free(*vp); + return -1; +} + +p_assign(name, v, flag) +char *name; +struct value *v; +char flag; +{ + (void) s_gettok(); + + if (p_expr(v, flag) < 0) { + p_synerror(); + return -1; + } + switch (v->v_type) { + case V_STR: + case V_NUM: + if (flag && var_set(name, v) == 0) { + p_memerror(); + val_free(*v); + return -1; + } + break; + } + return 0; +} diff --git a/usr.bin/window/parser3.c b/usr.bin/window/parser3.c new file mode 100644 index 0000000..d4aa80d --- /dev/null +++ b/usr.bin/window/parser3.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parser3.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "parser.h" + +/* + * = + * ? : + * || + * && + * | + * ^ + * & + * == != + * <= >= + * << >> + * + - + * * / % + * unary - + ~ ! + */ +p_expr(v, flag) +register struct value *v; +char flag; +{ + struct value t; + int ret; + + if (p_expr0(&t, flag) < 0) + return -1; + + if (token != T_ASSIGN) { + *v = t; + return 0; + } + switch (t.v_type) { + case V_NUM: + p_error("%d: Not a variable.", t.v_num); + case V_ERR: + t.v_str = 0; + break; + } + ret = p_assign(t.v_str, v, flag); + if (t.v_str != 0) + str_free(t.v_str); + return ret; +} + +/* + * ? : + */ +p_expr0(v, flag) +register struct value *v; +char flag; +{ + struct value t; + char true; + + if (p_expr1(v, flag) < 0) + return -1; + if (token != T_QUEST) + return 0; + switch (v->v_type) { + case V_NUM: + true = v->v_num != 0; + break; + case V_STR: + p_error("?: Numeric left operand required."); + str_free(v->v_str); + v->v_type = V_ERR; + case V_ERR: + flag = 0; + break; + } + (void) s_gettok(); + v->v_type = V_ERR; + if ((flag && true ? p_expr1(v, 1) : p_expr1(&t, 0)) < 0) + return -1; + if (token != T_COLON) { + val_free(*v); + p_synerror(); + return -1; + } + (void) s_gettok(); + return flag && !true ? p_expr1(v, 1) : p_expr1(&t, 0); +} + +/* + * || + */ +p_expr1(v, flag) +register struct value *v; +char flag; +{ + char true = 0; + + if (p_expr2(v, flag) < 0) + return -1; + if (token != T_OROR) + return 0; + for (;;) { + switch (v->v_type) { + case V_NUM: + v->v_num = true = true || v->v_num != 0; + break; + case V_STR: + p_error("||: Numeric operands required."); + str_free(v->v_str); + v->v_type = V_ERR; + case V_ERR: + flag = 0; + break; + } + if (token != T_OROR) + return 0; + (void) s_gettok(); + if (p_expr2(v, flag && !true) < 0) + return -1; + } +} + +/* + * && + */ +p_expr2(v, flag) +register struct value *v; +char flag; +{ + char true = 1; + + if (p_expr3_10(3, v, flag) < 0) + return -1; + if (token != T_ANDAND) + return 0; + for (;;) { + switch (v->v_type) { + case V_NUM: + v->v_num = true = true && v->v_num != 0; + break; + case V_STR: + p_error("&&: Numeric operands required."); + str_free(v->v_str); + v->v_type = V_ERR; + case V_ERR: + flag = 0; + break; + } + if (token != T_ANDAND) + return 0; + (void) s_gettok(); + if (p_expr3_10(3, v, flag && true) < 0) + return -1; + } + /*NOTREACHED*/ +} diff --git a/usr.bin/window/parser4.c b/usr.bin/window/parser4.c new file mode 100644 index 0000000..16ffb0c --- /dev/null +++ b/usr.bin/window/parser4.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parser4.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "parser.h" + +/* + * | 3 + * ^ 4 + * & 5 + * == != 6 + * < <= > >= 7 + * << >> 8 + * + - 9 + * * / % 10 + */ +p_expr3_10(level, v, flag) +register struct value *v; +char flag; +{ + struct value l, r; + int op; + char *opname; + + if ((level == 10 ? p_expr11(v, flag) + : p_expr3_10(level + 1, v, flag)) < 0) + return -1; + for (;;) { + switch (level) { + case 3: + if (token != T_OR) + return 0; + opname = "|"; + break; + case 4: + if (token != T_XOR) + return 0; + opname = "^"; + break; + case 5: + if (token != T_AND) + return 0; + opname = "&"; + break; + case 6: + if (token == T_EQ) + opname = "=="; + else if (token == T_NE) + opname = "!="; + else + return 0; + break; + case 7: + switch (token) { + case T_LT: + opname = "<"; + break; + case T_LE: + opname = "<="; + break; + case T_GT: + opname = ">"; + break; + case T_GE: + opname = ">="; + break; + default: + return 0; + } + break; + case 8: + if (token == T_LS) + opname = "<<"; + else if (token == T_RS) + opname = ">>"; + else + return 0; + break; + case 9: + if (token == T_PLUS) + opname = "+"; + else if (token == T_MINUS) + opname = "-"; + else + return 0; + break; + case 10: + switch (token) { + case T_MUL: + opname = "*"; + break; + case T_DIV: + opname = "/"; + break; + case T_MOD: + opname = "%"; + break; + default: + return 0; + } + break; + } + l = *v; + if (l.v_type == V_ERR) + flag = 0; + + op = token; + (void) s_gettok(); + if ((level == 10 ? p_expr11(&r, flag) + : p_expr3_10(level + 1, &r, flag)) < 0) { + p_synerror(); + val_free(l); + return -1; + } + + if (r.v_type == V_ERR) + flag = 0; + else switch (op) { + case T_EQ: + case T_NE: + case T_LT: + case T_LE: + case T_GT: + case T_GE: + case T_PLUS: + if (l.v_type == V_STR) { + if (r.v_type == V_NUM) + if (p_convstr(&r) < 0) + flag = 0; + } else + if (r.v_type == V_STR) + if (p_convstr(&l) < 0) + flag = 0; + break; + case T_LS: + case T_RS: + if (r.v_type == V_STR) { + char *p = r.v_str; + r.v_type = V_NUM; + r.v_num = strlen(p); + str_free(p); + } + break; + case T_OR: + case T_XOR: + case T_AND: + case T_MINUS: + case T_MUL: + case T_DIV: + case T_MOD: + default: + if (l.v_type == V_STR || r.v_type == V_STR) { + p_error("%s: Numeric operands required.", + opname); + flag = 0; + } + } + if (!flag) { + val_free(l); + val_free(r); + v->v_type = V_ERR; + if (p_abort()) + return -1; + continue; + } + + v->v_type = V_NUM; + switch (op) { + case T_EQ: + case T_NE: + case T_LT: + case T_LE: + case T_GT: + case T_GE: + if (l.v_type == V_STR) { + int tmp = strcmp(l.v_str, r.v_str); + str_free(l.v_str); + str_free(r.v_str); + l.v_type = V_NUM; + l.v_num = tmp; + r.v_type = V_NUM; + r.v_num = 0; + } + break; + } + switch (op) { + case T_OR: + v->v_num = l.v_num | r.v_num; + break; + case T_XOR: + v->v_num = l.v_num ^ r.v_num; + break; + case T_AND: + v->v_num = l.v_num & r.v_num; + break; + case T_EQ: + v->v_num = l.v_num == r.v_num; + break; + case T_NE: + v->v_num = l.v_num != r.v_num; + break; + case T_LT: + v->v_num = l.v_num < r.v_num; + break; + case T_LE: + v->v_num = l.v_num <= r.v_num; + break; + case T_GT: + v->v_num = l.v_num > r.v_num; + break; + case T_GE: + v->v_num = l.v_num >= r.v_num; + break; + case T_LS: + if (l.v_type == V_STR) { + int i; + if ((i = strlen(l.v_str)) > r.v_num) + i = r.v_num; + v->v_str = str_ncpy(l.v_str, i); + v->v_type = V_STR; + } else + v->v_num = l.v_num << r.v_num; + break; + case T_RS: + if (l.v_type == V_STR) { + int i; + if ((i = strlen(l.v_str)) > r.v_num) + i -= r.v_num; + else + i = 0; + v->v_str = str_cpy(l.v_str + i); + v->v_type = V_STR; + } else + v->v_num = l.v_num >> r.v_num; + break; + case T_PLUS: + if (l.v_type == V_STR) { + v->v_str = str_cat(l.v_str, r.v_str); + v->v_type = V_STR; + } else + v->v_num = l.v_num + r.v_num; + break; + case T_MINUS: + v->v_num = l.v_num - r.v_num; + break; + case T_MUL: + v->v_num = l.v_num * r.v_num; + break; + case T_DIV: + v->v_num = l.v_num / r.v_num; + break; + case T_MOD: + v->v_num = l.v_num % r.v_num; + break; + } + val_free(l); + val_free(r); + } + /*NOTREACHED*/ +} diff --git a/usr.bin/window/parser5.c b/usr.bin/window/parser5.c new file mode 100644 index 0000000..b179756 --- /dev/null +++ b/usr.bin/window/parser5.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)parser5.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "parser.h" +#include "var.h" + +/* + * unary $ $? + - ! ~ + */ +p_expr11(v, flag) +register struct value *v; +char flag; +{ + int op; + char *opname; + + switch (token) { + case T_DOLLAR: + opname = "$"; + break; + case T_DQ: + opname = "$?"; + break; + case T_PLUS: + opname = "unary +"; + break; + case T_MINUS: + opname = "unary -"; + break; + case T_NOT: + opname = "!"; + break; + case T_COMP: + opname = "~"; + break; + default: + return p_expr12(v, flag); + } + op = token; + (void) s_gettok(); + if (p_expr11(v, flag) < 0) + return -1; + switch (v->v_type) { + case V_NUM: + break; + case V_STR: + switch (op) { + case T_MINUS: + case T_NOT: + case T_COMP: + p_error("%s: Numeric operand required.", opname); + str_free(v->v_str); + v->v_type = V_ERR; + return 0; + } + break; + case V_ERR: + return 0; + } + switch (op) { + case T_DOLLAR: + case T_DQ: + if (v->v_type == V_NUM) { + int tmp = cx.x_type == X_BUF && cx.x_arg != 0 && + v->v_num > 0 && v->v_num <= cx.x_narg; + if (op == T_DQ) + v->v_num = tmp; + else if (tmp) + *v = cx.x_arg[v->v_num - 1]; + else { + p_error("%d: No such argument.", v->v_num); + v->v_type = V_ERR; + } + } else { + char *name = v->v_str; + struct var *r = var_lookup(name); + if (op == T_DQ) { + v->v_type = V_NUM; + v->v_num = r != 0; + } else if (r != 0) + *v = r->r_val; + else { + p_error("%s: Undefined variable.", name); + v->v_type = V_ERR; + } + str_free(name); + } + if (v->v_type == V_STR && (v->v_str = str_cpy(v->v_str)) == 0) { + p_memerror(); + return -1; + } + break; + case T_MINUS: + v->v_num = - v->v_num; + break; + case T_NOT: + v->v_num = ! v->v_num; + break; + case T_COMP: + v->v_num = ~ v->v_num; + break; + } + return 0; +} + +/* + * string, number, ( expr ) + * Plus function calls. + * + * Always return v_type == V_ERR when flag == 0. + */ +p_expr12(v, flag) +register struct value *v; +char flag; +{ + v->v_type = V_ERR; + switch (token) { + case T_NUM: + if (flag) { + v->v_type = V_NUM; + v->v_num = token_num; + } + (void) s_gettok(); + break; + case T_STR: + if (flag) { + v->v_type = V_STR; + v->v_str = token_str; + } else + str_free(token_str); + (void) s_gettok(); + break; + case T_LP: + (void) s_gettok(); + if (p_expr(v, flag) < 0) { + p_synerror(); + return -1; + } + if (token != T_RP) { + p_synerror(); + val_free(*v); + return -1; + } + (void) s_gettok(); + break; + default: + return -1; + } + while (token == T_LP) { + char *cmd; + + if (p_convstr(v) < 0) + return -1; + cmd = v->v_type == V_STR ? v->v_str : 0; + if (p_function(cmd, v, flag) < 0) { + if (cmd) + str_free(cmd); + return -1; + } + if (cmd) + str_free(cmd); + } + return 0; +} diff --git a/usr.bin/window/scanner.c b/usr.bin/window/scanner.c new file mode 100644 index 0000000..d10719c --- /dev/null +++ b/usr.bin/window/scanner.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)scanner.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "value.h" +#include "token.h" +#include "context.h" +#include "string.h" + +s_getc() +{ + register c; + + switch (cx.x_type) { + case X_FILE: + c = getc(cx.x_fp); + if (cx.x_bol && c != EOF) { + cx.x_bol = 0; + cx.x_lineno++; + } + if (c == '\n') + cx.x_bol = 1; + return c; + case X_BUF: + if (*cx.x_bufp != 0) + return *cx.x_bufp++ & 0xff; + else + return EOF; + } + /*NOTREACHED*/ +} + +s_ungetc(c) +{ + if (c == EOF) + return EOF; + switch (cx.x_type) { + case X_FILE: + cx.x_bol = 0; + return ungetc(c, cx.x_fp); + case X_BUF: + if (cx.x_bufp > cx.x_buf) + return *--cx.x_bufp = c; + else + return EOF; + } + /*NOTREACHED*/ +} + +s_gettok() +{ + char buf[100]; + register char *p = buf; + register c; + register state = 0; + +loop: + c = s_getc(); + switch (state) { + case 0: + switch (c) { + case ' ': + case '\t': + break; + case '\n': + case ';': + cx.x_token = T_EOL; + state = -1; + break; + case '#': + state = 1; + break; + case EOF: + cx.x_token = T_EOF; + state = -1; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '_': case '.': + *p++ = c; + state = 2; + break; + case '"': + state = 3; + break; + case '\'': + state = 4; + break; + case '\\': + switch (c = s_gettok1()) { + case -1: + break; + case -2: + state = 0; + break; + default: + *p++ = c; + state = 2; + } + break; + case '0': + cx.x_val.v_num = 0; + state = 10; + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + cx.x_val.v_num = c - '0'; + state = 11; + break; + case '>': + state = 20; + break; + case '<': + state = 21; + break; + case '=': + state = 22; + break; + case '!': + state = 23; + break; + case '&': + state = 24; + break; + case '|': + state = 25; + break; + case '$': + state = 26; + break; + case '~': + cx.x_token = T_COMP; + state = -1; + break; + case '+': + cx.x_token = T_PLUS; + state = -1; + break; + case '-': + cx.x_token = T_MINUS; + state = -1; + break; + case '*': + cx.x_token = T_MUL; + state = -1; + break; + case '/': + cx.x_token = T_DIV; + state = -1; + break; + case '%': + cx.x_token = T_MOD; + state = -1; + break; + case '^': + cx.x_token = T_XOR; + state = -1; + break; + case '(': + cx.x_token = T_LP; + state = -1; + break; + case ')': + cx.x_token = T_RP; + state = -1; + break; + case ',': + cx.x_token = T_COMMA; + state = -1; + break; + case '?': + cx.x_token = T_QUEST; + state = -1; + break; + case ':': + cx.x_token = T_COLON; + state = -1; + break; + case '[': + cx.x_token = T_LB; + state = -1; + break; + case ']': + cx.x_token = T_RB; + state = -1; + break; + default: + cx.x_val.v_num = c; + cx.x_token = T_CHAR; + state = -1; + break; + } + break; + case 1: /* got # */ + if (c == '\n' || c == EOF) { + (void) s_ungetc(c); + state = 0; + } + break; + case 2: /* unquoted string */ + switch (c) { + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '_': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (p < buf + sizeof buf - 1) + *p++ = c; + break; + case '"': + state = 3; + break; + case '\'': + state = 4; + break; + case '\\': + switch (c = s_gettok1()) { + case -2: + (void) s_ungetc(' '); + case -1: + break; + default: + if (p < buf + sizeof buf - 1) + *p++ = c; + } + break; + default: + (void) s_ungetc(c); + case EOF: + *p = 0; + cx.x_token = T_STR; + switch (*buf) { + case 'i': + if (buf[1] == 'f' && buf[2] == 0) + cx.x_token = T_IF; + break; + case 't': + if (buf[1] == 'h' && buf[2] == 'e' + && buf[3] == 'n' && buf[4] == 0) + cx.x_token = T_THEN; + break; + case 'e': + if (buf[1] == 'n' && buf[2] == 'd' + && buf[3] == 'i' && buf[4] == 'f' + && buf[5] == 0) + cx.x_token = T_ENDIF; + else if (buf[1] == 'l' && buf[2] == 's') + if (buf[3] == 'i' && buf[4] == 'f' + && buf[5] == 0) + cx.x_token = T_ELSIF; + else if (buf[3] == 'e' && buf[4] == 0) + cx.x_token = T_ELSE; + break; + } + if (cx.x_token == T_STR + && (cx.x_val.v_str = str_cpy(buf)) == 0) { + p_memerror(); + cx.x_token = T_EOF; + } + state = -1; + break; + } + break; + case 3: /* " quoted string */ + switch (c) { + case '\n': + (void) s_ungetc(c); + case EOF: + case '"': + state = 2; + break; + case '\\': + switch (c = s_gettok1()) { + case -1: + case -2: /* newlines are invisible */ + break; + default: + if (p < buf + sizeof buf - 1) + *p++ = c; + } + break; + default: + if (p < buf + sizeof buf - 1) + *p++ = c; + break; + } + break; + case 4: /* ' quoted string */ + switch (c) { + case '\n': + (void) s_ungetc(c); + case EOF: + case '\'': + state = 2; + break; + case '\\': + switch (c = s_gettok1()) { + case -1: + case -2: /* newlines are invisible */ + break; + default: + if (p < buf + sizeof buf - 1) + *p++ = c; + } + break; + default: + if (p < buf + sizeof buf - 1) + *p++ = c; + break; + } + break; + case 10: /* got 0 */ + switch (c) { + case 'x': + case 'X': + cx.x_val.v_num = 0; + state = 12; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + cx.x_val.v_num = c - '0'; + state = 13; + break; + case '8': case '9': + cx.x_val.v_num = c - '0'; + state = 11; + break; + default: + (void) s_ungetc(c); + state = -1; + cx.x_token = T_NUM; + } + break; + case 11: /* decimal number */ + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + cx.x_val.v_num = cx.x_val.v_num * 10 + c - '0'; + break; + default: + (void) s_ungetc(c); + state = -1; + cx.x_token = T_NUM; + } + break; + case 12: /* hex number */ + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + cx.x_val.v_num = cx.x_val.v_num * 16 + c - '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + cx.x_val.v_num = cx.x_val.v_num * 16 + c - 'a' + 10; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + cx.x_val.v_num = cx.x_val.v_num * 16 + c - 'A' + 10; + break; + default: + (void) s_ungetc(c); + state = -1; + cx.x_token = T_NUM; + } + break; + case 13: /* octal number */ + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + cx.x_val.v_num = cx.x_val.v_num * 8 + c - '0'; + break; + default: + (void) s_ungetc(c); + state = -1; + cx.x_token = T_NUM; + } + break; + case 20: /* got > */ + switch (c) { + case '=': + cx.x_token = T_GE; + state = -1; + break; + case '>': + cx.x_token = T_RS; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_GT; + state = -1; + } + break; + case 21: /* got < */ + switch (c) { + case '=': + cx.x_token = T_LE; + state = -1; + break; + case '<': + cx.x_token = T_LS; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_LT; + state = -1; + } + break; + case 22: /* got = */ + switch (c) { + case '=': + cx.x_token = T_EQ; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_ASSIGN; + state = -1; + } + break; + case 23: /* got ! */ + switch (c) { + case '=': + cx.x_token = T_NE; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_NOT; + state = -1; + } + break; + case 24: /* got & */ + switch (c) { + case '&': + cx.x_token = T_ANDAND; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_AND; + state = -1; + } + break; + case 25: /* got | */ + switch (c) { + case '|': + cx.x_token = T_OROR; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_OR; + state = -1; + } + break; + case 26: /* got $ */ + switch (c) { + case '?': + cx.x_token = T_DQ; + state = -1; + break; + default: + (void) s_ungetc(c); + cx.x_token = T_DOLLAR; + state = -1; + } + break; + default: + abort(); + } + if (state >= 0) + goto loop; + return cx.x_token; +} + +s_gettok1() +{ + register c; + register n; + + c = s_getc(); /* got \ */ + switch (c) { + case EOF: + return -1; + case '\n': + return -2; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + return c; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + break; + } + n = c - '0'; + c = s_getc(); /* got \[0-7] */ + if (c < '0' || c > '7') { + (void) s_ungetc(c); + return n; + } + n = n * 8 + c - '0'; + c = s_getc(); /* got \[0-7][0-7] */ + if (c < '0' || c > '7') { + (void) s_ungetc(c); + return n; + } + return n * 8 + c - '0'; +} diff --git a/usr.bin/window/startup.c b/usr.bin/window/startup.c new file mode 100644 index 0000000..d0926c0 --- /dev/null +++ b/usr.bin/window/startup.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "value.h" +#include "var.h" +#include "char.h" +#include "local.h" + +doconfig() +{ + char buf[100]; + char *home; + static char runcom[] = RUNCOM; + + if ((home = getenv("HOME")) == 0) + home = "."; + (void) sprintf(buf, "%.*s/%s", + (sizeof buf - sizeof runcom) / sizeof (char) - 1, + home, runcom); + return dosource(buf); +} + +/* + * The default is two windows of equal size. + */ +dodefault() +{ + struct ww *w; + register r = wwnrow / 2 - 1; + + if (openwin(1, r + 2, 0, wwnrow - r - 2, wwncol, default_nline, + (char *) 0, 1, 1, default_shellfile, default_shell) == 0) + return; + if ((w = openwin(0, 1, 0, r, wwncol, default_nline, + (char *) 0, 1, 1, default_shellfile, default_shell)) == 0) + return; + wwprintf(w, "Escape character is %s.\r\n", unctrl(escapec)); +} + +setvars() +{ + /* try to use a random ordering to balance the tree */ + (void) var_setnum("nrow", wwnrow); + (void) var_setnum("ncol", wwncol); + (void) var_setnum("baud", wwbaud); + (void) var_setnum("m_rev", WWM_REV); + (void) var_setnum("m_blk", WWM_BLK); + (void) var_setnum("m_ul", WWM_UL); + (void) var_setnum("m_grp", WWM_GRP); + (void) var_setnum("m_dim", WWM_DIM); + (void) var_setnum("m_usr", WWM_USR); + (void) var_setstr("term", wwterm); + (void) var_setnum("modes", wwavailmodes); +} diff --git a/usr.bin/window/string.c b/usr.bin/window/string.c new file mode 100644 index 0000000..a01f04f --- /dev/null +++ b/usr.bin/window/string.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)string.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "string.h" + +char *malloc(); + +char * +str_cpy(s) +register char *s; +{ + char *str; + register char *p; + + str = p = str_alloc(strlen(s) + 1); + if (p == 0) + return 0; + while (*p++ = *s++) + ; + return str; +} + +char * +str_ncpy(s, n) +register char *s; +register n; +{ + int l = strlen(s); + char *str; + register char *p; + + if (n > l) + n = l; + str = p = str_alloc(n + 1); + if (p == 0) + return 0; + while (--n >= 0) + *p++ = *s++; + *p = 0; + return str; +} + +char * +str_itoa(i) +int i; +{ + char buf[30]; + + (void) sprintf(buf, "%d", i); + return str_cpy(buf); +} + +char * +str_cat(s1, s2) +char *s1, *s2; +{ + char *str; + register char *p, *q; + + str = p = str_alloc(strlen(s1) + strlen(s2) + 1); + if (p == 0) + return 0; + for (q = s1; *p++ = *q++;) + ; + for (q = s2, p--; *p++ = *q++;) + ; + return str; +} + +/* + * match s against p. + * s can be a prefix of p with at least min characters. + */ +str_match(s, p, min) +register char *s, *p; +register min; +{ + for (; *s && *p && *s == *p; s++, p++, min--) + ; + return *s == *p || *s == 0 && min <= 0; +} + +#ifdef STR_DEBUG +char * +str_alloc(l) +int l; +{ + register struct string *s; + + s = (struct string *) malloc((unsigned)l + str_offset); + if (s == 0) + return 0; + if (str_head.s_forw == 0) + str_head.s_forw = str_head.s_back = &str_head; + s->s_forw = str_head.s_forw; + s->s_back = &str_head; + str_head.s_forw = s; + s->s_forw->s_back = s; + return s->s_data; +} + +str_free(str) +char *str; +{ + register struct string *s; + + for (s = str_head.s_forw; s != &str_head && s->s_data != str; + s = s->s_forw) + ; + if (s == &str_head) + abort(); + s->s_back->s_forw = s->s_forw; + s->s_forw->s_back = s->s_back; + free((char *)s); +} +#endif diff --git a/usr.bin/window/string.h b/usr.bin/window/string.h new file mode 100644 index 0000000..08cae56 --- /dev/null +++ b/usr.bin/window/string.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)string.h 8.1 (Berkeley) 6/6/93 + */ + +#define STR_DEBUG + +char *str_cpy(); +char *str_ncpy(); +char *str_cat(); +char *str_itoa(); + +#define str_cmp(a, b) strcmp(a, b) + +#ifdef STR_DEBUG +struct string { + struct string *s_forw; + struct string *s_back; + char s_data[1]; +}; + +struct string str_head; + +#define str_offset ((unsigned)str_head.s_data - (unsigned)&str_head) +#define str_stos(s) ((struct string *)((unsigned)(s) - str_offset)) + +char *str_alloc(); +int str_free(); +#else +#define str_free(s) free(s) +#define str_alloc(s) malloc(s) +#endif diff --git a/usr.bin/window/token.h b/usr.bin/window/token.h new file mode 100644 index 0000000..a37b23b --- /dev/null +++ b/usr.bin/window/token.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)token.h 8.1 (Berkeley) 6/6/93 + */ + +#define token (cx.x_token) +#define token_num (cx.x_val.v_num) +#define token_str (cx.x_val.v_str) + +#define T_EOL 1 +#define T_EOF 2 +#define T_COMP 3 +#define T_PLUS 4 +#define T_MINUS 5 +#define T_MUL 6 +#define T_DIV 7 +#define T_LP 8 +#define T_RP 9 +#define T_LB 10 +#define T_RB 11 +#define T_DOLLAR 12 +#define T_COMMA 13 +#define T_QUEST 14 +#define T_COLON 15 +#define T_CHAR 16 +#define T_STR 17 +#define T_NUM 18 +#define T_MOD 19 +#define T_XOR 20 +#define T_DQ 21 /* $? */ +#define T_GE 22 +#define T_RS 23 +#define T_GT 24 +#define T_LE 25 +#define T_LS 26 +#define T_LT 27 +#define T_EQ 28 +#define T_ASSIGN 29 +#define T_NE 30 +#define T_NOT 31 +#define T_ANDAND 32 +#define T_AND 33 +#define T_OROR 34 +#define T_OR 35 + +#define T_IF 40 +#define T_THEN 41 +#define T_ELSIF 42 +#define T_ELSE 43 +#define T_ENDIF 44 diff --git a/usr.bin/window/tt.h b/usr.bin/window/tt.h new file mode 100644 index 0000000..bd19bb3 --- /dev/null +++ b/usr.bin/window/tt.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tt.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Interface structure for the terminal drivers. + */ +struct tt { + /* startup and cleanup */ + int (*tt_start)(); + int (*tt_reset)(); + int (*tt_end)(); + + /* terminal functions */ + int (*tt_move)(); + int (*tt_insline)(); + int (*tt_delline)(); + int (*tt_inschar)(); + int (*tt_insspace)(); + int (*tt_delchar)(); + int (*tt_write)(); /* write a whole block */ + int (*tt_putc)(); /* write one character */ + int (*tt_clreol)(); + int (*tt_clreos)(); + int (*tt_clear)(); + int (*tt_scroll_down)(); + int (*tt_scroll_up)(); + int (*tt_setscroll)(); /* set scrolling region */ + int (*tt_setmodes)(); /* set display modes */ + int (*tt_set_token)(); /* define a token */ + int (*tt_put_token)(); /* refer to a defined token */ + int (*tt_compress)(); /* begin, end compression */ + int (*tt_checksum)(); /* compute checksum */ + int (*tt_checkpoint)(); /* checkpoint protocol */ + int (*tt_rint)(); /* input processing */ + + /* internal variables */ + char tt_modes; /* the current display modes */ + char tt_nmodes; /* the new modes for next write */ + char tt_insert; /* currently in insert mode */ + int tt_row; /* cursor row */ + int tt_col; /* cursor column */ + int tt_scroll_top; /* top of scrolling region */ + int tt_scroll_bot; /* bottom of scrolling region */ + + /* terminal info */ + int tt_nrow; /* number of display rows */ + int tt_ncol; /* number of display columns */ + char tt_availmodes; /* the display modes supported */ + char tt_wrap; /* has auto wrap around */ + char tt_retain; /* can retain below (db flag) */ + short tt_padc; /* the pad character */ + int tt_ntoken; /* number of compression tokens */ + int tt_token_min; /* minimun token size */ + int tt_token_max; /* maximum token size */ + int tt_set_token_cost; /* cost in addition to string */ + int tt_put_token_cost; /* constant cost */ + int tt_ack; /* checkpoint ack-nack flag */ + + /* the frame characters */ + short *tt_frame; + + /* ttflush() hook */ + int (*tt_flush)(); +}; +struct tt tt; + +/* + * tt_padc is used by the compression routine. + * It is a short to allow the driver to indicate that there is no padding. + */ +#define TT_PADC_NONE 0x100 + +/* + * List of terminal drivers. + */ +struct tt_tab { + char *tt_name; + int tt_len; + int (*tt_func)(); +}; +extern struct tt_tab tt_tab[]; + +/* + * Clean interface to termcap routines. + * Too may t's. + */ +char tt_strings[1024]; /* string buffer */ +char *tt_strp; /* pointer for it */ + +struct tt_str { + char *ts_str; + int ts_n; +}; + +struct tt_str *tttgetstr(); +struct tt_str *ttxgetstr(); /* tgetstr() and expand delays */ + +int tttputc(); +#define tttputs(s, n) tputs((s)->ts_str, (n), tttputc) +#define ttxputs(s) ttwrite((s)->ts_str, (s)->ts_n) + +/* + * Buffered output without stdio. + * These variables have different meanings from the ww_ob* variables. + * But I'm too lazy to think up different names. + */ +char *tt_ob; +char *tt_obp; +char *tt_obe; +#define ttputc(c) (tt_obp < tt_obe ? (*tt_obp++ = (c)) \ + : (ttflush(), *tt_obp++ = (c))) + +/* + * Convenience macros for the drivers + * They require char.h + */ +#define ttctrl(c) ttputc(ctrl(c)) +#define ttesc(c) (ttctrl('['), ttputc(c)) diff --git a/usr.bin/window/ttf100.c b/usr.bin/window/ttf100.c new file mode 100644 index 0000000..2b152f2 --- /dev/null +++ b/usr.bin/window/ttf100.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttf100.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +/* + * Freedom 100 + */ + +#define G (WWM_GRP << WWC_MSHIFT) +short f100_frame[16] = { + ' ', 'J'|G, 'K'|G, 'A'|G, + 'J'|G, 'J'|G, 'B'|G, 'M'|G, + 'K'|G, 'D'|G, 'K'|G, 'O'|G, + 'C'|G, 'L'|G, 'N'|G, 'I'|G +}; +extern struct tt_str *gen_AE, *gen_AS; + +tt_f100() +{ + static struct tt_str ae = { "\033%", 2 }; + static struct tt_str as = { "\033$", 2 }; + + if (tt_generic() < 0) + return -1; + tt.tt_frame = f100_frame; + tt.tt_availmodes |= WWM_GRP; + gen_AS = &as; + gen_AE = &ae; + return 0; +} diff --git a/usr.bin/window/ttgeneric.c b/usr.bin/window/ttgeneric.c new file mode 100644 index 0000000..4dddd21 --- /dev/null +++ b/usr.bin/window/ttgeneric.c @@ -0,0 +1,549 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttgeneric.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +char PC, *BC, *UP; +short ospeed; + + /* normal frame */ +short gen_frame[16] = { + ' ', '|', '-', '+', + '|', '|', '+', '+', + '-', '+', '-', '+', + '+', '+', '+', '+' +}; + + /* ANSI graphics frame */ +#define G (WWM_GRP << WWC_MSHIFT) +short ansi_frame[16] = { + ' ', 'x'|G, 'Q'|G, 'm'|G, + 'x'|G, 'x'|G, 'l'|G, 't'|G, + 'q'|G, 'j'|G, 'q'|G, 'v'|G, + 'k'|G, 'u'|G, 'w'|G, 'n'|G +}; +struct tt_str ansi_AS = { + "\033(0", 3 +}; + +struct tt_str *gen_PC; +struct tt_str *gen_CM; +struct tt_str *gen_IM; +struct tt_str *gen_IC; +struct tt_str *gen_ICn; +struct tt_str *gen_IP; +struct tt_str *gen_EI; +struct tt_str *gen_DC; +struct tt_str *gen_DCn; +struct tt_str *gen_AL; +struct tt_str *gen_ALn; +struct tt_str *gen_DL; +struct tt_str *gen_DLn; +struct tt_str *gen_CE; +struct tt_str *gen_CD; +struct tt_str *gen_CL; +struct tt_str *gen_VS; +struct tt_str *gen_VE; +struct tt_str *gen_TI; +struct tt_str *gen_TE; +struct tt_str *gen_SO; +struct tt_str *gen_SE; +struct tt_str *gen_US; +struct tt_str *gen_UE; +struct tt_str *gen_LE; +struct tt_str *gen_ND; +struct tt_str *gen_UP; +struct tt_str *gen_DO; +struct tt_str *gen_BC; +struct tt_str *gen_NL; +struct tt_str *gen_CR; +struct tt_str *gen_HO; +struct tt_str *gen_AS; +struct tt_str *gen_AE; +struct tt_str *gen_XS; +struct tt_str *gen_XE; +struct tt_str *gen_SF; +struct tt_str *gen_SFn; +struct tt_str *gen_SR; +struct tt_str *gen_SRn; +struct tt_str *gen_CS; +char gen_MI; +char gen_MS; +char gen_AM; +char gen_OS; +char gen_BS; +char gen_DA; +char gen_DB; +char gen_NS; +char gen_XN; +int gen_CO; +int gen_LI; +int gen_UG; +int gen_SG; + +gen_setinsert(new) +char new; +{ + if (new) { + if (gen_IM) + ttxputs(gen_IM); + } else + if (gen_EI) + ttxputs(gen_EI); + tt.tt_insert = new; +} + +gen_setmodes(new) +register new; +{ + register diff; + + diff = new ^ tt.tt_modes; + if (diff & WWM_REV) { + if (new & WWM_REV) { + if (gen_SO) + ttxputs(gen_SO); + } else + if (gen_SE) + ttxputs(gen_SE); + } + if (diff & WWM_UL) { + if (new & WWM_UL) { + if (gen_US) + ttxputs(gen_US); + } else + if (gen_UE) + ttxputs(gen_UE); + } + if (diff & WWM_GRP) { + if (new & WWM_GRP) { + if (gen_AS) + ttxputs(gen_AS); + } else + if (gen_AE) + ttxputs(gen_AE); + } + if (diff & WWM_USR) { + if (new & WWM_USR) { + if (gen_XS) + ttxputs(gen_XS); + } else + if (gen_XE) + ttxputs(gen_XE); + } + tt.tt_modes = new; +} + +gen_insline(n) +{ + if (tt.tt_modes) /* for concept 100 */ + gen_setmodes(0); + if (gen_ALn) + ttpgoto(gen_ALn, 0, n, gen_LI - tt.tt_row); + else + while (--n >= 0) + tttputs(gen_AL, gen_LI - tt.tt_row); +} + +gen_delline(n) +{ + if (tt.tt_modes) /* for concept 100 */ + gen_setmodes(0); + if (gen_DLn) + ttpgoto(gen_DLn, 0, n, gen_LI - tt.tt_row); + else + while (--n >= 0) + tttputs(gen_DL, gen_LI - tt.tt_row); +} + +gen_putc(c) +register char c; +{ + if (tt.tt_insert) + gen_setinsert(0); + if (tt.tt_nmodes != tt.tt_modes) + gen_setmodes(tt.tt_nmodes); + ttputc(c); + if (++tt.tt_col == gen_CO) + if (gen_XN) + tt.tt_col = tt.tt_row = -10; + else if (gen_AM) + tt.tt_col = 0, tt.tt_row++; + else + tt.tt_col--; +} + +gen_write(p, n) + register char *p; + register n; +{ + if (tt.tt_insert) + gen_setinsert(0); + if (tt.tt_nmodes != tt.tt_modes) + gen_setmodes(tt.tt_nmodes); + ttwrite(p, n); + tt.tt_col += n; + if (tt.tt_col == gen_CO) + if (gen_XN) + tt.tt_col = tt.tt_row = -10; + else if (gen_AM) + tt.tt_col = 0, tt.tt_row++; + else + tt.tt_col--; +} + +gen_move(row, col) +register int row, col; +{ + if (tt.tt_row == row && tt.tt_col == col) + return; + if (!gen_MI && tt.tt_insert) + gen_setinsert(0); + if (!gen_MS && tt.tt_modes) + gen_setmodes(0); + if (row < tt.tt_scroll_top || row > tt.tt_scroll_bot) + gen_setscroll(0, tt.tt_nrow - 1); + if (tt.tt_row == row) { + if (col == 0) { + ttxputs(gen_CR); + goto out; + } + if (tt.tt_col == col - 1) { + if (gen_ND) { + ttxputs(gen_ND); + goto out; + } + } else if (tt.tt_col == col + 1) { + if (gen_LE) { + ttxputs(gen_LE); + goto out; + } + } + } + if (tt.tt_col == col) { + if (tt.tt_row == row + 1) { + if (gen_UP) { + ttxputs(gen_UP); + goto out; + } + } else if (tt.tt_row == row - 1) { + ttxputs(gen_DO); + goto out; + } + } + if (gen_HO && col == 0 && row == 0) { + ttxputs(gen_HO); + goto out; + } + tttgoto(gen_CM, col, row); +out: + tt.tt_col = col; + tt.tt_row = row; +} + +gen_start() +{ + if (gen_VS) + ttxputs(gen_VS); + if (gen_TI) + ttxputs(gen_TI); + ttxputs(gen_CL); + tt.tt_col = tt.tt_row = 0; + tt.tt_insert = 0; + tt.tt_nmodes = tt.tt_modes = 0; +} + +gen_end() +{ + if (tt.tt_insert) + gen_setinsert(0); + if (gen_TE) + ttxputs(gen_TE); + if (gen_VE) + ttxputs(gen_VE); +} + +gen_clreol() +{ + if (tt.tt_modes) /* for concept 100 */ + gen_setmodes(0); + tttputs(gen_CE, gen_CO - tt.tt_col); +} + +gen_clreos() +{ + if (tt.tt_modes) /* for concept 100 */ + gen_setmodes(0); + tttputs(gen_CD, gen_LI - tt.tt_row); +} + +gen_clear() +{ + if (tt.tt_modes) /* for concept 100 */ + gen_setmodes(0); + ttxputs(gen_CL); +} + +gen_inschar(c) +register char c; +{ + if (!tt.tt_insert) + gen_setinsert(1); + if (tt.tt_nmodes != tt.tt_modes) + gen_setmodes(tt.tt_nmodes); + if (gen_IC) + tttputs(gen_IC, gen_CO - tt.tt_col); + ttputc(c); + if (gen_IP) + tttputs(gen_IP, gen_CO - tt.tt_col); + if (++tt.tt_col == gen_CO) + if (gen_XN) + tt.tt_col = tt.tt_row = -10; + else if (gen_AM) + tt.tt_col = 0, tt.tt_row++; + else + tt.tt_col--; +} + +gen_insspace(n) +{ + if (gen_ICn) + ttpgoto(gen_ICn, 0, n, gen_CO - tt.tt_col); + else + while (--n >= 0) + tttputs(gen_IC, gen_CO - tt.tt_col); +} + +gen_delchar(n) +{ + if (gen_DCn) + ttpgoto(gen_DCn, 0, n, gen_CO - tt.tt_col); + else + while (--n >= 0) + tttputs(gen_DC, gen_CO - tt.tt_col); +} + +gen_scroll_down(n) +{ + gen_move(tt.tt_scroll_bot, 0); + if (gen_SFn) + ttpgoto(gen_SFn, 0, n, n); + else + while (--n >= 0) + ttxputs(gen_SF); +} + +gen_scroll_up(n) +{ + gen_move(tt.tt_scroll_top, 0); + if (gen_SRn) + ttpgoto(gen_SRn, 0, n, n); + else + while (--n >= 0) + ttxputs(gen_SR); +} + +gen_setscroll(top, bot) +{ + tttgoto(gen_CS, bot, top); + tt.tt_scroll_top = top; + tt.tt_scroll_bot = bot; + tt.tt_row = tt.tt_col = -10; +} + +tt_generic() +{ + gen_PC = tttgetstr("pc"); + PC = gen_PC ? *gen_PC->ts_str : 0; + ospeed = wwospeed; + + gen_CM = ttxgetstr("cm"); /* may not work */ + gen_IM = ttxgetstr("im"); + gen_IC = tttgetstr("ic"); + gen_ICn = tttgetstr("IC"); + gen_IP = tttgetstr("ip"); + gen_EI = ttxgetstr("ei"); + gen_DC = tttgetstr("dc"); + gen_DCn = tttgetstr("DC"); + gen_AL = tttgetstr("al"); + gen_ALn = tttgetstr("AL"); + gen_DL = tttgetstr("dl"); + gen_DLn = tttgetstr("DL"); + gen_CE = tttgetstr("ce"); + gen_CD = tttgetstr("cd"); + gen_CL = ttxgetstr("cl"); + gen_VS = ttxgetstr("vs"); + gen_VE = ttxgetstr("ve"); + gen_TI = ttxgetstr("ti"); + gen_TE = ttxgetstr("te"); + gen_SO = ttxgetstr("so"); + gen_SE = ttxgetstr("se"); + gen_US = ttxgetstr("us"); + gen_UE = ttxgetstr("ue"); + gen_LE = ttxgetstr("le"); + gen_ND = ttxgetstr("nd"); + gen_UP = ttxgetstr("up"); + gen_DO = ttxgetstr("do"); + gen_BC = ttxgetstr("bc"); + gen_NL = ttxgetstr("nl"); + gen_CR = ttxgetstr("cr"); + gen_HO = ttxgetstr("ho"); + gen_AS = ttxgetstr("as"); + gen_AE = ttxgetstr("ae"); + gen_XS = ttxgetstr("XS"); + gen_XE = ttxgetstr("XE"); + gen_SF = ttxgetstr("sf"); + gen_SFn = ttxgetstr("SF"); + gen_SR = ttxgetstr("sr"); + gen_SRn = ttxgetstr("SR"); + gen_CS = ttxgetstr("cs"); + gen_MI = tgetflag("mi"); + gen_MS = tgetflag("ms"); + gen_AM = tgetflag("am"); + gen_OS = tgetflag("os"); + gen_BS = tgetflag("bs"); + gen_DA = tgetflag("da"); + gen_DB = tgetflag("db"); + gen_NS = tgetflag("ns"); + gen_XN = tgetflag("xn"); + gen_CO = tgetnum("co"); + gen_LI = tgetnum("li"); + gen_UG = tgetnum("ug"); + gen_SG = tgetnum("sg"); + if (gen_CL == 0 || gen_OS || gen_CM == 0) + return -1; + + /* + * Deal with obsolete termcap fields. + */ + if (gen_LE == 0) + if (gen_BC) + gen_LE = gen_BC; + else if (gen_BS) { + static struct tt_str bc = { "\b", 1 }; + gen_BC = &bc; + } + if (gen_NL == 0) { + static struct tt_str nl = { "\n", 1 }; + gen_NL = &nl; + } + if (gen_DO == 0) + gen_DO = gen_NL; + if (gen_CR == 0) { + static struct tt_str cr = { "\r", 1 }; + gen_CR = &cr; + } + /* + * Most terminal will scroll with "nl", but very few specify "sf". + * We shouldn't use "do" here. + */ + if (gen_SF == 0 && !gen_NS) + gen_SF = gen_NL; + BC = gen_LE ? gen_LE->ts_str : 0; + UP = gen_UP ? gen_UP->ts_str : 0; + /* + * Fix up display attributes that we can't handle, or don't + * really exist. + */ + if (gen_SG > 0) + gen_SO = 0; + if (gen_UG > 0 || gen_US && gen_SO && ttstrcmp(gen_US, gen_SO) == 0) + gen_US = 0; + + if (gen_IM && gen_IM->ts_n == 0) { + free((char *) gen_IM); + gen_IM = 0; + } + if (gen_EI && gen_EI->ts_n == 0) { + free((char *) gen_EI); + gen_EI = 0; + } + if (gen_IC && gen_IC->ts_n == 0) { + free((char *) gen_IC); + gen_IC = 0; + } + if (gen_IM) + tt.tt_inschar = gen_inschar; + else if (gen_IC) + tt.tt_insspace = gen_insspace; + if (gen_DC) + tt.tt_delchar = gen_delchar; + if (gen_AL) + tt.tt_insline = gen_insline; + if (gen_DL) + tt.tt_delline = gen_delline; + if (gen_CE) + tt.tt_clreol = gen_clreol; + if (gen_CD) + tt.tt_clreos = gen_clreos; + if (gen_SF) + tt.tt_scroll_down = gen_scroll_down; + /* + * Don't allow scroll_up if da or db but not cs. + * See comment in wwscroll.c. + */ + if (gen_SR && (gen_CS || !gen_DA && !gen_DB)) + tt.tt_scroll_up = gen_scroll_up; + if (gen_CS) + tt.tt_setscroll = gen_setscroll; + if (gen_SO) + tt.tt_availmodes |= WWM_REV; + if (gen_US) + tt.tt_availmodes |= WWM_UL; + if (gen_AS) + tt.tt_availmodes |= WWM_GRP; + if (gen_XS) + tt.tt_availmodes |= WWM_USR; + tt.tt_wrap = gen_AM; + tt.tt_retain = gen_DB; + tt.tt_ncol = gen_CO; + tt.tt_nrow = gen_LI; + tt.tt_start = gen_start; + tt.tt_end = gen_end; + tt.tt_write = gen_write; + tt.tt_putc = gen_putc; + tt.tt_move = gen_move; + tt.tt_clear = gen_clear; + tt.tt_setmodes = gen_setmodes; + tt.tt_frame = gen_AS && ttstrcmp(gen_AS, &ansi_AS) == 0 ? + ansi_frame : gen_frame; + return 0; +} diff --git a/usr.bin/window/tth19.c b/usr.bin/window/tth19.c new file mode 100644 index 0000000..b6dbcfe --- /dev/null +++ b/usr.bin/window/tth19.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)tth19.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include "char.h" + +/* +kb|h19|heath|h19-b|h19b|heathkit|heath-19|z19|zenith: + cr=^M:nl=^J:bl=^G:al=1*\EL:am:le=^H:bs:cd=\EJ:ce=\EK: + cl=\EE:cm=\EY%+ %+ :co#80:dc=\EN:dl=1*\EM:do=\EB: + ei=\EO:ho=\EH:im=\E@:li#24:mi:nd=\EC:as=\EF:ae=\EG:ms: + ta=^I:pt:sr=\EI:se=\Eq:so=\Ep:up=\EA:vs=\Ex4:ve=\Ey4: + kb=^h:ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\EH: + kn#8:k1=\ES:k2=\ET:k3=\EU:k4=\EV:k5=\EW: + l6=blue:l7=red:l8=white:k6=\EP:k7=\EQ:k8=\ER: + es:hs:ts=\Ej\Ex5\Ex1\EY8%+ \Eo:fs=\Ek\Ey5:ds=\Ey1: +*/ + +#define NCOL 80 +#define NROW 24 + +#define G (WWM_GRP << WWC_MSHIFT) +short h19_frame[16] = { + ' ', '`'|G, 'a'|G, 'e'|G, + '`'|G, '`'|G, 'f'|G, 'v'|G, + 'a'|G, 'd'|G, 'a'|G, 'u'|G, + 'c'|G, 't'|G, 's'|G, 'b'|G +}; + +extern struct tt_str *gen_VS; +extern struct tt_str *gen_VE; + +int h19_msp10c; + +#define PAD(ms10) { \ + register i; \ + for (i = ((ms10) + 5) / h19_msp10c; --i >= 0;) \ + ttputc('\0'); \ +} +#define ICPAD() PAD((NCOL - tt.tt_col) * 1) /* 0.1 ms per char */ +#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */ + +#define H19_SETINSERT(m) ttesc((tt.tt_insert = (m)) ? '@' : 'O') + +h19_setmodes(new) +register new; +{ + register diff; + + diff = new ^ tt.tt_modes; + if (diff & WWM_REV) + ttesc(new & WWM_REV ? 'p' : 'q'); + if (diff & WWM_GRP) + ttesc(new & WWM_REV ? 'F' : 'G'); + tt.tt_modes = new; +} + +h19_insline(n) +{ + while (--n >= 0) { + ttesc('L'); + ILPAD(); + } +} + +h19_delline(n) +{ + while (--n >= 0) { + ttesc('M'); + ILPAD(); + } +} + +h19_putc(c) +register char c; +{ + if (tt.tt_nmodes != tt.tt_modes) + (*tt.tt_setmodes)(tt.tt_nmodes); + if (tt.tt_insert) + H19_SETINSERT(0); + ttputc(c); + if (++tt.tt_col == NCOL) + tt.tt_col = NCOL - 1; +} + +h19_write(p, n) +register char *p; +register n; +{ + if (tt.tt_nmodes != tt.tt_modes) + (*tt.tt_setmodes)(tt.tt_nmodes); + if (tt.tt_insert) + H19_SETINSERT(0); + ttwrite(p, n); + tt.tt_col += n; + if (tt.tt_col == NCOL) + tt.tt_col = NCOL - 1; +} + +h19_move(row, col) +register char row, col; +{ + if (tt.tt_row == row) { + if (tt.tt_col == col) + return; + if (col == 0) { + ttctrl('m'); + goto out; + } + if (tt.tt_col == col - 1) { + ttesc('C'); + goto out; + } + if (tt.tt_col == col + 1) { + ttctrl('h'); + goto out; + } + } + if (tt.tt_col == col) { + if (tt.tt_row == row + 1) { + ttesc('A'); + goto out; + } + if (tt.tt_row == row - 1) { + ttctrl('j'); + goto out; + } + } + if (col == 0 && row == 0) { + ttesc('H'); + goto out; + } + ttesc('Y'); + ttputc(' ' + row); + ttputc(' ' + col); +out: + tt.tt_col = col; + tt.tt_row = row; +} + +h19_start() +{ + if (gen_VS) + ttxputs(gen_VS); + ttesc('w'); + ttesc('E'); + tt.tt_col = tt.tt_row = 0; + tt.tt_insert = 0; + tt.tt_nmodes = tt.tt_modes = 0; +} + +h19_end() +{ + if (tt.tt_insert) + H19_SETINSERT(0); + if (gen_VE) + ttxputs(gen_VE); + ttesc('v'); +} + +h19_clreol() +{ + ttesc('K'); +} + +h19_clreos() +{ + ttesc('J'); +} + +h19_clear() +{ + ttesc('E'); +} + +h19_inschar(c) +register char c; +{ + if (tt.tt_nmodes != tt.tt_modes) + (*tt.tt_setmodes)(tt.tt_nmodes); + if (!tt.tt_insert) + H19_SETINSERT(1); + ttputc(c); + if (tt.tt_insert) + ICPAD(); + if (++tt.tt_col == NCOL) + tt.tt_col = NCOL - 1; +} + +h19_delchar(n) +{ + while (--n >= 0) + ttesc('N'); +} + +h19_scroll_down(n) +{ + h19_move(NROW - 1, 0); + while (--n >= 0) + ttctrl('j'); +} + +h19_scroll_up(n) +{ + h19_move(0, 0); + while (--n >= 0) + ttesc('I'); +} + +tt_h19() +{ + float cpms = (float) wwbaud / 10000; /* char per ms */ + + h19_msp10c = 10 / cpms; /* ms per 10 char */ + gen_VS = ttxgetstr("vs"); + gen_VE = ttxgetstr("ve"); + + tt.tt_start = h19_start; + tt.tt_end = h19_end; + + tt.tt_insline = h19_insline; + tt.tt_delline = h19_delline; + tt.tt_inschar = h19_inschar; + tt.tt_delchar = h19_delchar; + tt.tt_clreol = h19_clreol; + tt.tt_clreos = h19_clreos; + tt.tt_clear = h19_clear; + tt.tt_move = h19_move; + tt.tt_write = h19_write; + tt.tt_putc = h19_putc; + tt.tt_scroll_down = h19_scroll_down; + tt.tt_scroll_up = h19_scroll_up; + tt.tt_setmodes = h19_setmodes; + + tt.tt_ncol = NCOL; + tt.tt_nrow = NROW; + tt.tt_availmodes = WWM_REV|WWM_GRP; + tt.tt_frame = h19_frame; + return 0; +} diff --git a/usr.bin/window/tth29.c b/usr.bin/window/tth29.c new file mode 100644 index 0000000..2482abf --- /dev/null +++ b/usr.bin/window/tth29.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)tth29.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include "char.h" + +/* + * H29 Driver + * + * WWM_USR mode is alternate character set. + * +kC|h29|heath-29|z29|zenith-29:\ + :am:bc=\ED:bt=\E-:cr=^M:do=^J:nl=^J:bl=^G:\ + :al=\EL:le=^H:bs:cd=\EJ:ce=\EK:cl=\EE:cm=\EY%+ %+ :co#80:dc=\EN:\ + :dl=1*\EM:do=\EB:ei=\EO:ho=\EH:im=\E@:li#24:mi:nd=\EC:as=\EF:ae=\EG:\ + :ms:ta=^I:pt:sr=\EI:se=\Eq:so=\Ep:up=\EA:vs=\Ex4:ve=\Ey4:\ + :kb=^H:ku=\EA:kd=\EB:kl=\ED:kr=\EC:kh=\EH:kn#1:k0=\E~:l0=HOME:\ + :k1=\ES:k2=\ET:k3=\EU:k4=\EV:k5=\EW:k6=\EP:k7=\EQ:k8=\ER:k9=\E01:\ + :es:hs:ts=\Ej\Ex5\Ex1\EY8%+ \Eo:fs=\Ek\Ey5:ds=\Ey1:us=\Es8:ue=\Es0: + * + */ + +h29_setmodes(new) +register new; +{ + register modes = '0'; + + if (new & WWM_REV) + modes += 0x01; + if (new & WWM_BLK) + modes += 0x02; + if (new & WWM_DIM) + modes += 0x04; + if (new & WWM_UL) + modes += 0x08; + if (new & WWM_USR) + modes += 0x10; + ttesc('s'); + ttputc(modes); + if (new & WWM_GRP) { + if ((tt.tt_modes & WWM_GRP) == 0) + ttesc('F'); + } else + if (tt.tt_modes & WWM_GRP) + ttesc('G'); + tt.tt_modes = new; +} + +tt_h29() +{ + if (tt_h19() < 0) + return -1; + tt.tt_setmodes = h29_setmodes; + tt.tt_availmodes |= WWM_BLK|WWM_UL|WWM_DIM|WWM_USR; + return 0; +} diff --git a/usr.bin/window/ttinit.c b/usr.bin/window/ttinit.c new file mode 100644 index 0000000..8b82872 --- /dev/null +++ b/usr.bin/window/ttinit.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttinit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +int tt_h19(); +int tt_h29(); +int tt_f100(); +int tt_tvi925(); +int tt_wyse75(); +int tt_wyse60(); +int tt_zapple(); +int tt_zentec(); +int tt_generic(); +struct tt_tab tt_tab[] = { + { "h19", 3, tt_h19 }, + { "h29", 3, tt_h29 }, + { "f100", 4, tt_f100 }, + { "tvi925", 6, tt_tvi925 }, + { "wyse75", 6, tt_wyse75 }, + { "wyse60", 6, tt_wyse60 }, + { "w60", 3, tt_wyse60 }, + { "zapple", 6, tt_zapple }, + { "zentec", 6, tt_zentec }, + { "generic", 0, tt_generic }, + 0 +}; + +ttinit() +{ + int i; + register struct tt_tab *tp; + register char *p, *q; + register char *t; + + tt_strp = tt_strings; + + /* + * Set output buffer size to about 1 second of output time. + */ + i = MIN(wwbaud/10, 512); + if ((tt_ob = malloc((unsigned) i)) == 0) { + wwerrno = WWE_NOMEM; + return -1; + } + tt_obp = tt_ob; + tt_obe = tt_ob + i; + + /* + * Use the standard name of the terminal (i.e. the second + * name in termcap). + */ + for (p = wwtermcap; *p && *p != '|' && *p != ':'; p++) + ; + if (*p == '|') + p++; + for (q = p; *q && *q != '|' && *q != ':'; q++) + ; + if (q != p && (t = malloc((unsigned) (q - p + 1))) != 0) { + wwterm = t; + while (p < q) + *t++ = *p++; + *t = 0; + } + for (tp = tt_tab; tp->tt_name != 0; tp++) + if (strncmp(tp->tt_name, wwterm, tp->tt_len) == 0) + break; + if (tp->tt_name == 0) { + wwerrno = WWE_BADTERM; + return -1; + } + if ((*tp->tt_func)() < 0) { + wwerrno = WWE_CANTDO; + return -1; + } + if (wwgetttysize(0, &tt.tt_nrow, &tt.tt_ncol) < 0) + return -1; + tt.tt_scroll_top = 0; + tt.tt_scroll_bot = tt.tt_nrow - 1; + return 0; +} diff --git a/usr.bin/window/ttoutput.c b/usr.bin/window/ttoutput.c new file mode 100644 index 0000000..5c582d6 --- /dev/null +++ b/usr.bin/window/ttoutput.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttoutput.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include + +/* + * Buffered output package. + * We need this because stdio fails on non-blocking writes. + */ + +ttflush() +{ + register char *p; + register n = tt_obp - tt_ob; + extern errno; + + if (n == 0) + return; + if (tt.tt_checksum) + (*tt.tt_checksum)(tt_ob, n); + if (tt.tt_flush) { + (*tt.tt_flush)(); + return; + } + wwnflush++; + for (p = tt_ob; p < tt_obp;) { + wwnwr++; + n = write(1, p, tt_obp - p); + if (n < 0) { + wwnwre++; + if (errno != EWOULDBLOCK) { + /* can't deal with this */ + p = tt_obp; + } + } else if (n == 0) { + /* what to do? */ + wwnwrz++; + } else { + wwnwrc += n; + p += n; + } + } + tt_obp = tt_ob; +} + +ttputs(s) +register char *s; +{ + while (*s) + ttputc(*s++); +} + +ttwrite(s, n) + register char *s; + register n; +{ + switch (n) { + case 0: + break; + case 1: + ttputc(*s); + break; + case 2: + if (tt_obe - tt_obp < 2) + ttflush(); + *tt_obp++ = *s++; + *tt_obp++ = *s; + break; + case 3: + if (tt_obe - tt_obp < 3) + ttflush(); + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s; + break; + case 4: + if (tt_obe - tt_obp < 4) + ttflush(); + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s; + break; + case 5: + if (tt_obe - tt_obp < 5) + ttflush(); + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s++; + *tt_obp++ = *s; + break; + default: + while (n > 0) { + register m; + + while ((m = tt_obe - tt_obp) == 0) + ttflush(); + if ((m = tt_obe - tt_obp) > n) + m = n; + bcopy(s, tt_obp, m); + tt_obp += m; + s += m; + n -= m; + } + } +} diff --git a/usr.bin/window/tttermcap.c b/usr.bin/window/tttermcap.c new file mode 100644 index 0000000..a1e8508 --- /dev/null +++ b/usr.bin/window/tttermcap.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)tttermcap.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "tt.h" + +char *tgetstr(); +char *tgoto(); +char *malloc(); + +tttputc(c) +{ + ttputc(c); +} + +ttxputc(c) +{ + *tt_strp++ = c; +} + +struct tt_str * +tttgetstr(str) + char *str; +{ + register struct tt_str *s; + + if ((str = tgetstr(str, &tt_strp)) == 0) + return 0; + if ((s = (struct tt_str *) malloc(sizeof *s)) == 0) + return 0; + s->ts_str = str; + s->ts_n = tt_strp - s->ts_str - 1; + return s; +} + +struct tt_str * +ttxgetstr(str) + char *str; +{ + register struct tt_str *s; + char buf[100]; + char *bufp = buf; + + if (tgetstr(str, &bufp) == 0) + return 0; + if ((s = (struct tt_str *) malloc(sizeof *s)) == 0) + return 0; + s->ts_str = tt_strp; + tputs(buf, 1, ttxputc); + s->ts_n = tt_strp - s->ts_str; + *tt_strp++ = 0; + return s; +} + +tttgoto(s, col, row) + struct tt_str *s; +{ + register char *p = s->ts_str; + + ttputs(tgoto(p, col, row)); + for (p += s->ts_n; *--p == 0;) + ttputc(0); +} + +ttpgoto(s, col, row, n) + struct tt_str *s; +{ + + tputs(tgoto(s->ts_str, col, row), n, tttputc); +} + +ttstrcmp(a, b) + register struct tt_str *a, *b; +{ + int n, r; + + if (r = bcmp(a->ts_str, b->ts_str, + (n = a->ts_n - b->ts_n) < 0 ? a->ts_n : b->ts_n)) + return r; + return n; +} diff --git a/usr.bin/window/tttvi925.c b/usr.bin/window/tttvi925.c new file mode 100644 index 0000000..4f9ae2f --- /dev/null +++ b/usr.bin/window/tttvi925.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Barto at Celerity Computer Corp. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)tttvi925.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +/* + * Televideo 925 as emulated by Microterm. + */ + +#define G (WWM_GRP << WWC_MSHIFT) +short tvi925_frame[16] = { + ' ', '~'|G, '|'|G, 'c'|G, + '~'|G, '~'|G, '`'|G, 'e'|G, + '|'|G, 'a'|G, '|'|G, 'g'|G, + 'b'|G, 'f'|G, 'h'|G, 'd'|G +}; + +tt_tvi925() +{ + + if (tt_generic() < 0) + return -1; + tt.tt_availmodes |= WWM_GRP; + tt.tt_frame = tvi925_frame; + return 0; +} diff --git a/usr.bin/window/ttwyse60.c b/usr.bin/window/ttwyse60.c new file mode 100644 index 0000000..8efff55 --- /dev/null +++ b/usr.bin/window/ttwyse60.c @@ -0,0 +1,76 @@ +/* + * Copyright 1987 by David C. Elliott, MIPS Computer Systems. + * + * Unlimited redistribution allowed as long as this notice + * is kept intact. + */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David C. Elliott, of MIPS Computer Systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttwyse60.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +#define G (WWM_GRP << WWC_MSHIFT) +short wyse60_frame[16] = { + ' ', '6'|G, ':'|G, '1'|G, + '6'|G, '6'|G, '2'|G, '4'|G, + ':'|G, '5'|G, ':'|G, '='|G, + '3'|G, '9'|G, '0'|G, '0'|G +}; + +extern struct tt_str *gen_AS; +extern struct tt_str *gen_AE; + +tt_wyse60() +{ + static struct tt_str ae = { "\033H\003", 3 }; + static struct tt_str as = { "\033H\002", 3 }; + + if (tt_generic() < 0) + return -1; + tt.tt_availmodes |= WWM_GRP; + tt.tt_frame = wyse60_frame; + if (gen_AS == 0) + gen_AS = &as; + if (gen_AE == 0) + gen_AE = &ae; + return 0; +} diff --git a/usr.bin/window/ttwyse75.c b/usr.bin/window/ttwyse75.c new file mode 100644 index 0000000..8424d0d --- /dev/null +++ b/usr.bin/window/ttwyse75.c @@ -0,0 +1,76 @@ +/* + * Copyright 1987 by David C. Elliott, MIPS Computer Systems. + * + * Unlimited redistribution allowed as long as this notice + * is kept intact. + */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David C. Elliott, of MIPS Computer Systems. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttwyse75.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +#define G (WWM_GRP << WWC_MSHIFT) +short wyse75_frame[16] = { + ' ', 'x'|G, 'q'|G, 'm'|G, + 'x'|G, 'x'|G, 'l'|G, 't'|G, + 'q'|G, 'j'|G, 'q'|G, 'v'|G, + 'k'|G, 'u'|G, 'w'|G, 'v'|G +}; + +extern struct tt_str *gen_AS; +extern struct tt_str *gen_AE; + +tt_wyse75() +{ + static struct tt_str ae = { "\033(B", 3 }; + static struct tt_str as = { "\033(0", 3 }; + + if (tt_generic() < 0) + return -1; + tt.tt_availmodes |= WWM_GRP; + tt.tt_frame = wyse75_frame; + if (gen_AS == 0) + gen_AS = &as; + if (gen_AE == 0) + gen_AE = &ae; + return 0; +} diff --git a/usr.bin/window/ttzapple.c b/usr.bin/window/ttzapple.c new file mode 100644 index 0000000..a285712 --- /dev/null +++ b/usr.bin/window/ttzapple.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttzapple.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include "char.h" + +/* +zz|zapple|perfect apple:\ + :am:pt:co#80:li#24:le=^H:nd=^F:up=^K:do=^J:\ + :ho=\E0:ll=\E1:cm=\E=%+ %+ :ch=\E<%+ :cv=\E>%+ :\ + :cl=\E4:ce=\E2:cd=\E3:rp=\E@%.%+ :\ + :so=\E+:se=\E-:\ + :dc=\Ec:DC=\EC%+ :ic=\Ei:IC=\EI%+ :\ + :al=\Ea:AL=\EA%+ :dl=\Ed:DL=\ED%+ :\ + :sf=\Ef:SF=\EF%+ :sr=\Er:SR=\ER%+ :cs=\E?%+ %+ :\ + :is=\E-\ET : +*/ + +#define NCOL 80 +#define NROW 24 +#define TOKEN_MAX 32 + +extern short gen_frame[]; + + /* for error correction */ +int zz_ecc; +int zz_lastc; + + /* for checkpointing */ +int zz_sum; + +zz_setmodes(new) +{ + if (new & WWM_REV) { + if ((tt.tt_modes & WWM_REV) == 0) + ttesc('+'); + } else + if (tt.tt_modes & WWM_REV) + ttesc('-'); + tt.tt_modes = new; +} + +zz_insline(n) +{ + if (n == 1) + ttesc('a'); + else { + ttesc('A'); + ttputc(n + ' '); + } +} + +zz_delline(n) +{ + if (n == 1) + ttesc('d'); + else { + ttesc('D'); + ttputc(n + ' '); + } +} + +zz_putc(c) + char c; +{ + if (tt.tt_nmodes != tt.tt_modes) + zz_setmodes(tt.tt_nmodes); + ttputc(c); + if (++tt.tt_col == NCOL) + tt.tt_col = 0, tt.tt_row++; +} + +zz_write(p, n) + register char *p; + register n; +{ + if (tt.tt_nmodes != tt.tt_modes) + zz_setmodes(tt.tt_nmodes); + ttwrite(p, n); + tt.tt_col += n; + if (tt.tt_col == NCOL) + tt.tt_col = 0, tt.tt_row++; +} + +zz_move(row, col) + register row, col; +{ + register x; + + if (tt.tt_row == row) { +same_row: + if ((x = col - tt.tt_col) == 0) + return; + if (col == 0) { + ttctrl('m'); + goto out; + } + switch (x) { + case 2: + ttctrl('f'); + case 1: + ttctrl('f'); + goto out; + case -2: + ttctrl('h'); + case -1: + ttctrl('h'); + goto out; + } + if ((col & 7) == 0 && x > 0 && x <= 16) { + ttctrl('i'); + if (x > 8) + ttctrl('i'); + goto out; + } + ttesc('<'); + ttputc(col + ' '); + goto out; + } + if (tt.tt_col == col) { + switch (row - tt.tt_row) { + case 2: + ttctrl('j'); + case 1: + ttctrl('j'); + goto out; + case -2: + ttctrl('k'); + case -1: + ttctrl('k'); + goto out; + } + if (col == 0) { + if (row == 0) + goto home; + if (row == NROW - 1) + goto ll; + } + ttesc('>'); + ttputc(row + ' '); + goto out; + } + if (col == 0) { + if (row == 0) { +home: + ttesc('0'); + goto out; + } + if (row == tt.tt_row + 1) { + /* + * Do newline first to match the sequence + * for scroll down and return + */ + ttctrl('j'); + ttctrl('m'); + goto out; + } + if (row == NROW - 1) { +ll: + ttesc('1'); + goto out; + } + } + /* favor local motion for better compression */ + if (row == tt.tt_row + 1) { + ttctrl('j'); + goto same_row; + } + if (row == tt.tt_row - 1) { + ttctrl('k'); + goto same_row; + } + ttesc('='); + ttputc(' ' + row); + ttputc(' ' + col); +out: + tt.tt_col = col; + tt.tt_row = row; +} + +zz_start() +{ + ttesc('T'); + ttputc(TOKEN_MAX + ' '); + ttesc('U'); + ttputc('!'); + zz_ecc = 1; + zz_lastc = -1; + ttesc('v'); + ttflush(); + zz_sum = 0; + zz_setscroll(0, NROW - 1); + zz_clear(); + zz_setmodes(0); +} + +zz_reset() +{ + zz_setscroll(0, NROW - 1); + tt.tt_modes = WWM_REV; + zz_setmodes(0); + tt.tt_col = tt.tt_row = -10; +} + +zz_end() +{ + ttesc('T'); + ttputc(' '); + ttesc('U'); + ttputc(' '); + zz_ecc = 0; +} + +zz_clreol() +{ + ttesc('2'); +} + +zz_clreos() +{ + ttesc('3'); +} + +zz_clear() +{ + ttesc('4'); + tt.tt_col = tt.tt_row = 0; +} + +zz_insspace(n) +{ + if (n == 1) + ttesc('i'); + else { + ttesc('I'); + ttputc(n + ' '); + } +} + +zz_delchar(n) +{ + if (n == 1) + ttesc('c'); + else { + ttesc('C'); + ttputc(n + ' '); + } +} + +zz_scroll_down(n) +{ + if (n == 1) + if (tt.tt_row == NROW - 1) + ttctrl('j'); + else + ttesc('f'); + else { + ttesc('F'); + ttputc(n + ' '); + } +} + +zz_scroll_up(n) +{ + if (n == 1) + ttesc('r'); + else { + ttesc('R'); + ttputc(n + ' '); + } +} + +zz_setscroll(top, bot) +{ + ttesc('?'); + ttputc(top + ' '); + ttputc(bot + ' '); + tt.tt_scroll_top = top; + tt.tt_scroll_bot = bot; +} + +int zz_debug = 0; + +zz_set_token(t, s, n) + char *s; +{ + if (tt.tt_nmodes != tt.tt_modes) + zz_setmodes(tt.tt_nmodes); + if (zz_debug) { + char buf[100]; + zz_setmodes(WWM_REV); + (void) sprintf(buf, "%02x=", t); + ttputs(buf); + tt.tt_col += 3; + } + ttputc(0x80); + ttputc(t + 1); + s[n - 1] |= 0x80; + ttwrite(s, n); + s[n - 1] &= ~0x80; +} + +/*ARGSUSED*/ +zz_put_token(t, s, n) + char *s; +{ + if (tt.tt_nmodes != tt.tt_modes) + zz_setmodes(tt.tt_nmodes); + if (zz_debug) { + char buf[100]; + zz_setmodes(WWM_REV); + (void) sprintf(buf, "%02x>", t); + ttputs(buf); + tt.tt_col += 3; + } + ttputc(t + 0x81); +} + +zz_rint(p, n) + char *p; +{ + register i; + register char *q; + + if (!zz_ecc) + return n; + for (i = n, q = p; --i >= 0;) { + register c = (unsigned char) *p++; + + if (zz_lastc == 0) { + switch (c) { + case 0: + *q++ = 0; + zz_lastc = -1; + break; + case 1: /* start input ecc */ + zz_ecc = 2; + zz_lastc = -1; + wwnreadstat++; + break; + case 2: /* ack checkpoint */ + tt.tt_ack = 1; + zz_lastc = -1; + wwnreadack++; + break; + case 3: /* nack checkpoint */ + tt.tt_ack = -1; + zz_lastc = -1; + wwnreadnack++; + break; + default: + zz_lastc = c; + wwnreadec++; + } + } else if (zz_ecc == 1) { + if (c) + *q++ = c; + else + zz_lastc = 0; + } else { + if (zz_lastc < 0) { + zz_lastc = c; + } else if (zz_lastc == c) { + *q++ = zz_lastc; + zz_lastc = -1; + } else { + wwnreadec++; + zz_lastc = c; + } + } + } + return q - (p - n); +} + +zz_checksum(p, n) + register char *p; + register n; +{ + while (--n >= 0) { + register c = *p++ & 0x7f; + c ^= zz_sum; + zz_sum = c << 1 | c >> 11 & 1; + } +} + +zz_compress(flag) +{ + if (flag) + tt.tt_checksum = 0; + else + tt.tt_checksum = zz_checksum; +} + +zz_checkpoint() +{ + static char x[] = { ctrl('['), 'V', 0, 0 }; + + zz_checksum(x, sizeof x); + ttesc('V'); + ttputc(' ' + (zz_sum & 0x3f)); + ttputc(' ' + (zz_sum >> 6 & 0x3f)); + ttflush(); + zz_sum = 0; +} + +tt_zapple() +{ + tt.tt_insspace = zz_insspace; + tt.tt_delchar = zz_delchar; + tt.tt_insline = zz_insline; + tt.tt_delline = zz_delline; + tt.tt_clreol = zz_clreol; + tt.tt_clreos = zz_clreos; + tt.tt_scroll_down = zz_scroll_down; + tt.tt_scroll_up = zz_scroll_up; + tt.tt_setscroll = zz_setscroll; + tt.tt_availmodes = WWM_REV; + tt.tt_wrap = 1; + tt.tt_retain = 0; + tt.tt_ncol = NCOL; + tt.tt_nrow = NROW; + tt.tt_start = zz_start; + tt.tt_reset = zz_reset; + tt.tt_end = zz_end; + tt.tt_write = zz_write; + tt.tt_putc = zz_putc; + tt.tt_move = zz_move; + tt.tt_clear = zz_clear; + tt.tt_setmodes = zz_setmodes; + tt.tt_frame = gen_frame; + tt.tt_padc = TT_PADC_NONE; + tt.tt_ntoken = 127; + tt.tt_set_token = zz_set_token; + tt.tt_put_token = zz_put_token; + tt.tt_token_min = 1; + tt.tt_token_max = TOKEN_MAX; + tt.tt_set_token_cost = 2; + tt.tt_put_token_cost = 1; + tt.tt_compress = zz_compress; + tt.tt_checksum = zz_checksum; + tt.tt_checkpoint = zz_checkpoint; + tt.tt_reset = zz_reset; + tt.tt_rint = zz_rint; + return 0; +} diff --git a/usr.bin/window/ttzentec.c b/usr.bin/window/ttzentec.c new file mode 100644 index 0000000..97fbb07 --- /dev/null +++ b/usr.bin/window/ttzentec.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)ttzentec.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +/* + * Zentec 1021 + * + * We let the termcap entry specify how to enter and exit graphics mode, + * since it varies with what the terminal is emulating. + */ + +#define G (WWM_GRP << WWC_MSHIFT) +short zentec_frame[16] = { + ' ', 'x'|G, 'q'|G, 'm'|G, + 'x'|G, 'x'|G, 'l'|G, 't'|G, + 'q'|G, 'j'|G, 'q'|G, 'v'|G, + 'k'|G, 'u'|G, 'w'|G, 'n'|G +}; + +tt_zentec() +{ + if (tt_generic() < 0) + return -1; + if (tt.tt_availmodes | WWM_GRP) + tt.tt_frame = zentec_frame; + return 0; +} diff --git a/usr.bin/window/value.h b/usr.bin/window/value.h new file mode 100644 index 0000000..28a1162 --- /dev/null +++ b/usr.bin/window/value.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)value.h 8.1 (Berkeley) 6/6/93 + */ + +struct value { + char v_type; + union { + int V_num; + char *V_str; + } v_un; +}; +#define v_num v_un.V_num +#define v_str v_un.V_str + +#define V_NUM 1 +#define V_STR 2 +#define V_ERR 3 + +#define val_free(v) ((v).v_type == V_STR ? str_free((v).v_str) : 0) diff --git a/usr.bin/window/var.c b/usr.bin/window/var.c new file mode 100644 index 0000000..638dc95 --- /dev/null +++ b/usr.bin/window/var.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)var.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "value.h" +#include "var.h" +#include "string.h" + +char *malloc(); + +struct var * +var_set1(head, name, v) +struct var **head; +char *name; +struct value *v; +{ + register struct var **p; + register struct var *r; + struct value val; + + /* do this first, easier to recover */ + val = *v; + if (val.v_type == V_STR && val.v_str != 0 && + (val.v_str = str_cpy(val.v_str)) == 0) + return 0; + if (*(p = var_lookup1(head, name)) == 0) { + r = (struct var *) malloc(sizeof (struct var)); + if (r == 0) { + val_free(val); + return 0; + } + if ((r->r_name = str_cpy(name)) == 0) { + val_free(val); + free((char *) r); + return 0; + } + r->r_left = r->r_right = 0; + *p = r; + } else { + r = *p; + val_free(r->r_val); + } + r->r_val = val; + return r; +} + +struct var * +var_setstr1(head, name, str) +struct var **head; +char *name; +char *str; +{ + struct value v; + + v.v_type = V_STR; + v.v_str = str; + return var_set1(head, name, &v); +} + +struct var * +var_setnum1(head, name, num) +struct var **head; +char *name; +int num; +{ + struct value v; + + v.v_type = V_NUM; + v.v_num = num; + return var_set1(head, name, &v); +} + +var_unset1(head, name) +struct var **head; +char *name; +{ + register struct var **p; + register struct var *r; + + if (*(p = var_lookup1(head, name)) == 0) + return -1; + r = *p; + *p = r->r_left; + while (*p != 0) + p = &(*p)->r_right; + *p = r->r_right; + val_free(r->r_val); + str_free(r->r_name); + free((char *) r); + return 0; +} + +struct var ** +var_lookup1(p, name) +register struct var **p; +register char *name; +{ + register cmp; + + while (*p != 0) { + if ((cmp = strcmp(name, (*p)->r_name)) < 0) + p = &(*p)->r_left; + else if (cmp > 0) + p = &(*p)->r_right; + else + break; + } + return p; +} + +var_walk1(r, func, a) +register struct var *r; +int (*func)(); +{ + if (r == 0) + return 0; + if (var_walk1(r->r_left, func, a) < 0 || (*func)(a, r) < 0 + || var_walk1(r->r_right, func, a) < 0) + return -1; + return 0; +} diff --git a/usr.bin/window/var.h b/usr.bin/window/var.h new file mode 100644 index 0000000..95fd611 --- /dev/null +++ b/usr.bin/window/var.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)var.h 8.1 (Berkeley) 6/6/93 + */ + +struct var { + struct var *r_left; + struct var *r_right; + char *r_name; + struct value r_val; +}; + +struct var *var_set1(); +struct var *var_setstr1(); +struct var *var_setnum1(); +struct var **var_lookup1(); + +#define var_set(n, v) var_set1(&var_head, n, v) +#define var_setstr(n, s) var_setstr1(&var_head, n, s) +#define var_setnum(n, i) var_setnum1(&var_head, n, i) +#define var_unset(n) var_unset1(&var_head, n) +#define var_lookup(n) (*var_lookup1(&var_head, n)) +#define var_walk(f, a) var_walk1(var_head, f, a) + +struct var *var_head; /* secret, shhh */ diff --git a/usr.bin/window/win.c b/usr.bin/window/win.c new file mode 100644 index 0000000..7eabf23 --- /dev/null +++ b/usr.bin/window/win.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)win.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "defs.h" +#include "char.h" + +/* + * Higher level routines for dealing with windows. + * + * There are two types of windows: user window, and information window. + * User windows are the ones with a pty and shell. Information windows + * are for displaying error messages, and other information. + * + * The windows are doubly linked in overlapping order and divided into + * two groups: foreground and normal. Information + * windows are always foreground. User windows can be either. + * Addwin() adds a window to the list at the top of one of the two groups. + * Deletewin() deletes a window. Front() moves a window to the front + * of its group. Wwopen(), wwadd(), and wwdelete() should never be called + * directly. + */ + +/* + * Open a user window. + */ +struct ww * +openwin(id, row, col, nrow, ncol, nline, label, haspty, hasframe, shf, sh) +char *label; +char haspty, hasframe; +char *shf, **sh; +{ + register struct ww *w; + + if (id < 0 && (id = findid()) < 0) + return 0; + if (row + nrow <= 0 || row > wwnrow - 1 + || col + ncol <= 0 || col > wwncol - 1) { + error("Illegal window position."); + return 0; + } + w = wwopen(haspty ? WWO_PTY : WWO_SOCKET, nrow, ncol, row, col, nline); + if (w == 0) { + error("Can't open window: %s.", wwerror()); + return 0; + } + w->ww_id = id; + window[id] = w; + w->ww_hasframe = hasframe; + w->ww_alt = w->ww_w; + if (label != 0 && setlabel(w, label) < 0) + error("No memory for label."); + wwcursor(w, 1); + /* + * We have to do this little maneuver to make sure + * addwin() puts w at the top, so we don't waste an + * insert and delete operation. + */ + setselwin((struct ww *)0); + addwin(w, 0); + setselwin(w); + if (wwspawn(w, shf, sh) < 0) { + error("Can't execute %s: %s.", shf, wwerror()); + closewin(w); + return 0; + } + return w; +} + +findid() +{ + register i; + + for (i = 0; i < NWINDOW && window[i] != 0; i++) + ; + if (i >= NWINDOW) { + error("Too many windows."); + return -1; + } + return i; +} + +struct ww * +findselwin() +{ + register struct ww *w, *s = 0; + register i; + + for (i = 0; i < NWINDOW; i++) + if ((w = window[i]) != 0 && w != selwin && + (s == 0 || + !isfg(w) && (w->ww_order < s->ww_order || isfg(s)))) + s = w; + return s; +} + +/* + * Close a user window. Close all if w == 0. + */ +closewin(w) +register struct ww *w; +{ + char didit = 0; + register i; + + if (w != 0) { + closewin1(w); + didit++; + } else + for (i = 0; i < NWINDOW; i++) { + if ((w = window[i]) == 0) + continue; + closewin1(w); + didit++; + } + if (didit) { + if (selwin == 0) + if (lastselwin != 0) { + setselwin(lastselwin); + lastselwin = 0; + } else if (w = findselwin()) + setselwin(w); + if (lastselwin == 0 && selwin) + if (w = findselwin()) + lastselwin = w; + reframe(); + } +} + +/* + * Open an information (display) window. + */ +struct ww * +openiwin(nrow, label) +char *label; +{ + register struct ww *w; + + if ((w = wwopen(0, nrow, wwncol, 2, 0, 0)) == 0) + return 0; + w->ww_mapnl = 1; + w->ww_hasframe = 1; + w->ww_nointr = 1; + w->ww_noupdate = 1; + w->ww_unctrl = 1; + w->ww_id = -1; + w->ww_center = 1; + (void) setlabel(w, label); + addwin(w, 1); + reframe(); + return w; +} + +/* + * Close an information window. + */ +closeiwin(w) +struct ww *w; +{ + closewin1(w); + reframe(); +} + +closewin1(w) +register struct ww *w; +{ + if (w == selwin) + selwin = 0; + if (w == lastselwin) + lastselwin = 0; + if (w->ww_id >= 0 && w->ww_id < NWINDOW) + window[w->ww_id] = 0; + if (w->ww_label) + str_free(w->ww_label); + deletewin(w); + wwclose(w); +} + +/* + * Move the window to the top of its group. + * Don't do it if already fully visible. + * Wwvisible() doesn't work for tinted windows. + * But anything to make it faster. + * Always reframe() if doreframe is true. + */ +front(w, doreframe) +register struct ww *w; +char doreframe; +{ + if (w->ww_back != (isfg(w) ? framewin : fgwin) && !wwvisible(w)) { + deletewin(w); + addwin(w, isfg(w)); + doreframe = 1; + } + if (doreframe) + reframe(); +} + +/* + * Add a window at the top of normal windows or foreground windows. + * For normal windows, we put it behind the current window. + */ +addwin(w, fg) +register struct ww *w; +char fg; +{ + if (fg) { + wwadd(w, framewin); + if (fgwin == framewin) + fgwin = w; + } else + wwadd(w, selwin != 0 && selwin != w && !isfg(selwin) + ? selwin : fgwin); +} + +/* + * Delete a window. + */ +deletewin(w) +register struct ww *w; +{ + if (fgwin == w) + fgwin = w->ww_back; + wwdelete(w); +} + +reframe() +{ + register struct ww *w; + + wwunframe(framewin); + for (w = wwhead.ww_back; w != &wwhead; w = w->ww_back) + if (w->ww_hasframe) { + wwframe(w, framewin); + labelwin(w); + } +} + +labelwin(w) +register struct ww *w; +{ + int mode = w == selwin ? WWM_REV : 0; + + if (!w->ww_hasframe) + return; + if (w->ww_id >= 0) { + char buf[2]; + + buf[0] = w->ww_id + '1'; + buf[1] = 0; + wwlabel(w, framewin, 1, buf, mode); + } + if (w->ww_label) { + int col; + + if (w->ww_center) { + col = (w->ww_w.nc - strlen(w->ww_label)) / 2; + col = MAX(3, col); + } else + col = 3; + wwlabel(w, framewin, col, w->ww_label, mode); + } +} + +stopwin(w) + register struct ww *w; +{ + if (w->ww_pty >= 0 && w->ww_ispty && wwstoptty(w->ww_pty) < 0) + error("Can't stop output: %s.", wwerror()); + else + w->ww_stopped = 1; +} + +startwin(w) + register struct ww *w; +{ + if (w->ww_pty >= 0 && w->ww_ispty && wwstarttty(w->ww_pty) < 0) + error("Can't start output: %s.", wwerror()); + else + w->ww_stopped = 0; +} + +sizewin(w, nrow, ncol) +register struct ww *w; +{ + struct ww *back = w->ww_back; + + w->ww_alt.nr = w->ww_w.nr; + w->ww_alt.nc = w->ww_w.nc; + wwdelete(w); + if (wwsize(w, nrow, ncol) < 0) + error("Can't resize window: %s.", wwerror()); + wwadd(w, back); + reframe(); +} + +waitnl(w) +struct ww *w; +{ + (void) waitnl1(w, "[Type any key to continue]"); +} + +more(w, always) +register struct ww *w; +char always; +{ + int c; + char uc = w->ww_unctrl; + + if (!always && w->ww_cur.r < w->ww_w.b - 2) + return 0; + c = waitnl1(w, "[Type escape to abort, any other key to continue]"); + w->ww_unctrl = 0; + wwputs("\033E", w); + w->ww_unctrl = uc; + return c == ctrl('[') ? 2 : 1; +} + +waitnl1(w, prompt) +register struct ww *w; +char *prompt; +{ + char uc = w->ww_unctrl; + + w->ww_unctrl = 0; + front(w, 0); + wwprintf(w, "\033Y%c%c\033sA%s\033rA ", + w->ww_w.nr - 1 + ' ', ' ', prompt); /* print on last line */ + wwcurtowin(w); + while (wwpeekc() < 0) + wwiomux(); + w->ww_unctrl = uc; + return wwgetc(); +} diff --git a/usr.bin/window/window.1 b/usr.bin/window/window.1 new file mode 100644 index 0000000..425cce0 --- /dev/null +++ b/usr.bin/window/window.1 @@ -0,0 +1,947 @@ +.\" Copyright (c) 1985, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Edward Wang at The University of California, Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)window.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt WINDOW 1 +.Os BSD 4.3 +.Sh NAME +.Nm window +.Nd window environment +.Sh SYNOPSIS +.Nm window +.Op Fl t +.Op Fl f +.Op Fl d +.Op Fl e Ar escape-char +.Op Fl c Ar command +.Sh DESCRIPTION +.Nm Window +implements a window environment on +.Tn ASCII +terminals. +.Pp +A window is a rectangular portion of the physical terminal +screen associated with a set of processes. Its size and +position can be changed by the user at any time. Processes +communicate with their window in the same way they normally +interact with a terminal\-through their standard input, output, +and diagnostic file descriptors. The window program handles the +details of redirecting input and output to and from the +windows. At any one time, only one window can receive +input from the keyboard, but all windows can simultaneously send output +to the display. +.Pp +When +.Nm window +starts up, the commands (see long commands below) +contained in the file +.Pa .windowrc +in the user's home directory are +executed. If it does not exist, two equal sized windows spanning +the terminal screen are created by default. +.Pp +The command line options are +.Bl -tag -width Fl +.It Fl t +Turn on terse mode (see +.Ic terse +command below). +.It Fl f +Fast. Don't perform any startup action. +.It Fl d +Ignore +.Pa .windowrc +and create the two default +windows instead. +.It Fl e Ar escape-char +Set the escape character to +.Ar escape-char . +.Ar Escape-char +can be a single character, or in the form +.Ic ^X +where +.Ar X +is any character, meaning +.No control\- Ns Ar X . +.It Fl c Ar command +Execute the string +.Ar command +as a long command (see below) +before doing anything else. +.El +.Pp +Windows can overlap and are framed as necessary. Each window +is named by one of the digits ``1'' to ``9''. This one-character +identifier, as well as a user definable label string, are displayed +with the window on the top edge of its frame. A window can be +designated to be in the +.Ar foreground , +in which case it will always be +on top of all normal, non-foreground windows, and can be covered +only by other foreground windows. A window need not be completely +within the edges of the terminal screen. Thus a large window +(possibly larger than the screen) may be positioned to show only +a portion of its full size. +.Pp +Each window has a cursor and a set of control functions. Most intelligent +terminal operations such as line and +character deletion and insertion are supported. Display modes +such as underlining and reverse video are available if they are +supported by the terminal. In addition, +similar to terminals with multiple pages of memory, +each window has a text buffer which can have more lines than the window +itself. +.Ss Process Environment +With each newly created window, a shell program is spawned with its +process environment tailored to that window. Its standard input, +output, and diagnostic file descriptors are bound to one end of either +a pseudo-terminal +.Xr (pty 4 ) +or a +.Ux +domain socket +.Xr (socketpair 4 ) . +If a pseudo-terminal is used, then its special +characters and modes (see +.Xr stty 1 ) +are copied from the physical +terminal. A +.Xr termcap 5 +entry tailored to this window is created +and passed as environment +.Xr (environ 5 ) +variable +.Ev TERMCAP . +The termcap entry contains the window's size and +characteristics as well as information from the physical terminal, +such as the existence of underline, reverse video, and other display +modes, and the codes produced by the terminal's function keys, +if any. In addition, the window size attributes of the pseudo-terminal +are set to reflect the size of this window, and updated whenever +it is changed by the user. In particular, the editor +.Xr vi 1 +uses +this information to redraw its display. +.Ss Operation +During normal execution, +.Nm window +can be in one of two states: +conversation mode and command mode. In conversation mode, the +terminal's real cursor is placed at the cursor position of a particular +window--called the current window--and input from the keyboard is sent +to the process in that window. The current window is always +on top of all other windows, except those in foreground. In addition, +it is set apart by highlighting its identifier and label in reverse video. +.Pp +Typing +.Nm window Ns 's +escape character (normally +.Ic ^P ) +in conversation +mode switches it into command mode. In command mode, the top line of +the terminal screen becomes the command prompt window, and +.Nm window +interprets input from the keyboard as commands to manipulate windows. +.Pp +There are two types of commands: short commands are usually one or two +key strokes; long commands are strings either typed by the user in the +command window (see the +.Dq Ic \&: +command below), or read from a file (see +.Ic source +below). +.Ss Short Commands +Below, +.Ar \&# +represents one of the digits ``1'' to ``9'' +corresponding to the windows 1 to 9. +.Ic ^X +means +.No control\- Ns Ar X , +where +.Ar X +is any character. In particular, +.Ic ^^ +is +.Li control\-^. +.Ar Escape +is the escape key, or +.Ic ^\&[ . +.Bl -tag -width Ds +.It Ar # +Select window +.Ar # +as the current window +and return to conversation mode. +.It Ic \&% Ns Ar # +Select window +.Ar # +but stay in command mode. +.It Ic ^^ +Select the previous window and return to conversation +mode. This is useful for toggling between two windows. +.It Ic escape +Return to conversation mode. +.It Ic ^P +Return to conversation mode and write +.Ic ^P +to the +current window. Thus, typing two +.Ic ^P Ns 's +in conversation +mode sends one to the current window. If the +.Nm window +escape is changed to some other character, that +character takes the place of +.Ic ^P +here. +.It Ic ? +List a short summary of commands. +.It Ic ^L +Refresh the screen. +.It Ic q +Exit +.Nm window . +Confirmation is requested. +.It Ic ^Z +Suspend +.Nm window . +.It Ic w +Create a new window. The user is prompted for the positions +of the upper left and lower right corners of the window. +The cursor is placed on the screen and the keys ``h'', ``j'', +``k'', and ``l'' +move the cursor left, down, up, and right, respectively. +The keys ``H'', ``J'', ``K'', and ``L'' move the cursor to the respective +limits of the screen. Typing a number before the movement keys +repeats the movement that number of times. Return enters the cursor position +as the upper left corner of the window. The lower right corner +is entered in the same manner. During this process, +the placement of the new window is indicated by a rectangular +box drawn on the screen, corresponding to where the new window +will be framed. Typing escape at any point +cancels this command. +.Pp +This window becomes the current window, +and is given the first available ID. The default buffer size +is used (see +.Ar default_nline +command below). +.Pp +Only fully visible windows can be created this way. +.It Ic c Ns Ar # +Close window +.Ar # . +The process in the window is sent +the hangup signal (see +.Xr kill 1 ) . +.Xr Csh 1 +should +handle this signal correctly and cause no problems. +.It Ic m Ns Ar # +Move window +.Ar # +to another location. A box in the shape +of the window is drawn on +the screen to indicate the new position of the window, and the same keys as +those for the +.Ic w +command are used to position the box. The +window can be moved partially off-screen. +.It Ic M Ns Ar # +Move window +.Ar # +to its previous position. +.It Ic s Ns Ar # +Change the size of window +.Ar # . +The user is prompted +to enter the new lower right corner of the window. A box +is drawn to indicate the new window size. The same +keys used in +.Ic w +and +.Ic m +are used to enter the position. +.It Ic S Ns Ar # +Change window +.Ar # +to its previous size. +.It Ic ^Y +Scroll the current window up by one line. +.It Ic ^E +Scroll the current window down by one line. +.It Ic ^U +Scroll the current window up by half the window size. +.It Ic ^D +Scroll the current window down by half the window size. +.It Ic ^B +Scroll the current window up by the full window size. +.It Ic ^F +Scroll the current window down by the full window size. +.It Ic h +Move the cursor of the current window left by one column. +.It Ic j +Move the cursor of the current window down by one line. +.It Ic k +Move the cursor of the current window up by one line. +.It Ic l +Move the cursor of the current window right by one column. +.It Ic y +Yank. The user is prompted to enter two points within the current +window. Then the content of the current window between those two points +is saved in the yank buffer. +.It Ic p +Put. The content of the yank buffer is written to the current +window as input. +.It Ic ^S +Stop output in the current window. +.It Ic ^Q +Start output in the current window. +.It Ic : +Enter a line to be executed as long commands. +Normal line +editing characters (erase character, erase word, erase line) +are supported. +.El +.Ss Long Commands +Long commands are a sequence of statements +parsed much like a programming language, with a syntax +similar to that of C. Numeric and string expressions and variables +are supported, as well as conditional statements. +.Pp +There are two data types: string and number. A string is a sequence +of letters or digits beginning with a letter. ``_'' and ``.'' are +considered letters. Alternately, non-alphanumeric characters can +be included in strings by quoting them in ``"'' or escaping them +with ``\\''. In addition, the ``\\'' sequences of C are supported, +both inside and outside quotes (e.g., ``\\n'' is a new line, +``\\r'' a carriage return). For example, these are legal strings: +abcde01234, "&#$^*&#", ab"$#"cd, ab\\$\\#cd, "/usr/ucb/window". +.Pp +A number is an integer value in one of three forms: +a decimal number, an octal number preceded by ``0'', +or a hexadecimal number preceded by ``0x'' or ``0X''. The natural +machine integer size is used (i.e., the signed integer type +of the C compiler). As in C, a non-zero number represents +a boolean true. +.Pp +The character ``#'' begins a comment which terminates at the +end of the line. +.Pp +A statement is either a conditional or an expression. Expression +statements are terminated with a new line or ``;''. To continue +an expression on the next line, terminate the first line with ``\\''. +.Ss Conditional Statement +.Nm Window +has a single control structure: +the fully bracketed if statement in the form +.Pp +.Bd -literal -offset indent -compact +if then +\t +\t... +elsif then +\t +\t... +else +\t +\t... +endif +.Ed +.Pp +The +.Ic else +and +.Ic elsif +parts are optional, and the latter can +be repeated any number of times. + +must be numeric. +.Ss Expressions +Expressions in +.Nm window +are similar to those in the +C language, with most C operators supported on numeric +operands. In addition, some are overloaded to operate on strings. +.Pp +When an expression is used as a statement, its value is discarded +after evaluation. Therefore, only expressions with side +effects (assignments and function calls) are useful as statements. +.Pp +Single valued (no arrays) variables are supported, of both +numeric and string values. Some variables are predefined. They +are listed below. +.Pp +The operators in order of increasing precedence: +.Bl -tag -width Fl +.It Xo +.Aq Va expr1 +.Ic = +.Aq Va expr2 +.Xc +Assignment. The variable of name +.Aq Va expr1 , +which must be string valued, +is assigned the result of +.Aq Va expr2 . +Returns the value of +.Aq Va expr2 . +.It Xo +.Aq Va expr1 +.Ic ? +.Aq Va expr2 +.Ic : +.Aq Va expr3 +.Xc +Returns the value of +.Aq Va expr2 +if +.Aq Va expr1 +evaluates true +(non-zero numeric value); returns the value of +.Aq Va expr3 +otherwise. Only +one of +.Aq Va expr2 +and +.Aq Va expr3 +is evaluated. +.Aq Va Expr1 +must +be numeric. +.It Xo +.Aq Va expr1 +.Ic \&|\&| +.Aq Va expr2 +.Xc +Logical or. Numeric values only. Short circuit evaluation is supported +(i.e., if +.Aq Va expr1 +evaluates true, then +.Aq Va expr2 +is not evaluated). +.It Xo +.Aq Va expr1 +.Ic \&&\&& +.Aq Va expr2 +.Xc +Logical and with short circuit evaluation. Numeric values only. +.It Xo +.Aq Va expr1 +.Ic \&| +.Aq Va expr2 +.Xc +Bitwise or. Numeric values only. +.It Xo +.Aq Va expr1 +.Ic ^ +.Aq Va expr2 +.Xc +Bitwise exclusive or. Numeric values only. +.It Xo +.Aq Va expr1 +.Ic \&& +.Aq Va expr2 +.Xc +Bitwise and. Numeric values only. +.It Xo +.Aq Va expr1 +.Ic == +.Aq Va expr2 , +.Aq Va expr1 +.Ic != +.Aq expr2 +.Xc +Comparison (equal and not equal, respectively). The boolean +result (either 1 or 0) of the comparison is returned. The +operands can be numeric or string valued. One string operand +forces the other to be converted to a string in necessary. +.It Xo +.Aq Va expr1 +.Ic < +.Aq Va expr2 , +.Aq Va expr1 +.Ic > +.Aq Va expr2 , +.Aq Va expr1 +.Ic <= +.Aq Va expr2 , +.Xc +Less than, greater than, less than or equal to, +greater than or equal to. Both numeric and string values, with +automatic conversion as above. +.It Xo +.Aq Va expr1 +.Ic << +.Aq Va expr2 , +.Aq Va expr1 +.Ic >> +.Aq Va expr2 +.Xc +If both operands are numbers, +.Aq Va expr1 +is bit +shifted left (or right) by +.Aq Va expr2 +bits. If +.Aq Va expr1 +is +a string, then its first (or last) +.Aq Va expr2 +characters are +returns (if +.Aq Va expr2 +is also a string, then its length is used +in place of its value). +.It Xo +.Aq Va expr1 +.Ic + +.Aq Va expr2 , +.Aq Va expr1 +.Ic - +.Aq Va expr2 +.Xc +Addition and subtraction on numbers. For ``+'', if one +argument is a string, then the other is converted to a string, +and the result is the concatenation of the two strings. +.It Xo +.Aq Va expr1 +.Ic \&* +.Aq Va expr2 , +.Aq Va expr1 +.Ic \&/ +.Aq Va expr2 , +.Aq Va expr1 +.Ic \&% +.Aq Va expr2 +.Xc +Multiplication, division, modulo. Numbers only. +.It Xo +.Ic \- Ns Aq Va expr , +.Ic ~ Ns Aq Va expr , +.Ic \&! Ns Aq Va expr , +.Ic \&$ Ns Aq Va expr , +.Ic \&$? Ns Aq Va expr +.Xc +The first three are unary minus, bitwise complement and logical complement +on numbers only. The operator, ``$'', takes +.Aq Va expr +and returns +the value of the variable of that name. If +.Aq Va expr +is numeric +with value +.Ar n +and it appears within an alias macro (see below), +then it refers to the nth argument of the alias invocation. ``$?'' +tests for the existence of the variable +.Aq Va expr , +and returns 1 +if it exists or 0 otherwise. +.It Xo +.Ao Va expr Ac Ns Pq Aq Ar arglist +.Xc +Function call. +.Aq Va Expr +must be a string that is the unique +prefix of the name of a builtin +.Nm window +function +or the full name of a user defined alias macro. In the case of a builtin +function, +.Aq Ar arglist +can be in one of two forms: +.Bd -literal -offset indent +, , ... +argname1 = , argname2 = , ... +.Ed +.Pp +The two forms can in fact be intermixed, but the result is +unpredictable. Most arguments can be omitted; default values will +be supplied for them. The +.Ar argnames +can be unique prefixes +of the argument names. The commas separating +arguments are used only to disambiguate, and can usually be omitted. +.Pp +Only the first argument form is valid for user defined aliases. Aliases +are defined using the +.Ic alias +builtin function (see below). Arguments +are accessed via a variant of the variable mechanism (see ``$'' operator +above). +.Pp +Most functions return value, but some are used for side effect +only and so must be used as statements. When a function or an alias is used +as a statement, the parentheses surrounding +the argument list may be omitted. Aliases return no value. +.El +.Ss Builtin Functions +The arguments are listed by name in their natural +order. Optional arguments are in square brackets +.Sq Op . +Arguments +that have no names are in angle brackets +.Sq <> . +An argument meant to be a boolean flag (often named +.Ar flag ) +can be one of +.Ar on , +.Ar off , +.Ar yes , +.Ar no , +.Ar true , +or +.Ar false , +with +obvious meanings, or it can be a numeric expression, +in which case a non-zero value is true. +.Bl -tag -width Fl +.It Xo +.Ic alias Ns Po Bq Aq Ar string , +.Bq Aq Ar string\-list Pc +.Xc +If no argument is given, all currently defined alias macros are +listed. Otherwise, +.Aq Ar string +is defined as an alias, +with expansion +.Aq Ar string\-list > . +The previous definition of +.Aq Ar string , +if any, is returned. Default for +.Aq Ar string\-list +is no change. +.It Ic close Ns Pq Aq Ar window\-list +Close the windows specified in +.Aq Ar window\-list . +If +.Aq Ar window\-list +is the word +.Ar all , +than all windows are closed. No value is returned. +.It Ic cursormodes Ns Pq Bq Ar modes +Set the window cursor to +.Ar modes . +.Ar Modes +is the bitwise +or of the mode bits defined as the variables +.Ar m_ul +(underline), +.Ar m_rev +(reverse video), +.Ar m_blk +(blinking), +and +.Ar m_grp +(graphics, terminal dependent). Return +value is the previous modes. Default is no change. +For example, +.Li cursor($m_rev$m_blk) +sets the window cursors to blinking +reverse video. +.It Ic default_nline Ns Pq Bq Ar nline +Set the default buffer size to +.Ar nline . +Initially, it is +48 lines. Returns the old default buffer size. Default is +no change. Using a very large buffer can slow the program down +considerably. +.It Ic default_shell Ns Pq Bq Aq Ar string\-list +Set the default window shell program to +.Aq Ar string\-list . +Returns +the first string in the old shell setting. Default is no change. Initially, +the default shell is taken from the environment variable +.Ev SHELL . +.It Ic default_smooth Ns Pq Bq Ar flag +Set the default value of the +.Ar smooth +argument +to the command +.Nm window +(see below). The argument +is a boolean flag (one of +.Ar on , +.Ar off , +.Ar yes , +.Ar no , +.Ar true , +.Ar false , +or a number, +as described above). Default is no change. +The old value (as a number) is returned. +The initial value is 1 (true). +.It Xo +.Ic echo Ns ( Op Ar window , +.Bq Aq Ar string\-list ) +.Xc +Write the list of strings, +.Aq Ar string-list , +to +.Nm window , +separated +by spaces and terminated with a new line. The strings are only +displayed in the window, the processes in the window are not +involved (see +.Ic write +below). No value is returned. Default +is the current window. +.It Ic escape Ns Pq Bq Ar escapec +Set the escape character to +.Ar escape-char . +Returns the old +escape character as a one-character string. Default is no +change. +.Ar Escapec +can be a string of a single character, or +in the form +.Fl ^X , +meaning +.No control\- Ns Ar X . +.It Xo +.Ic foreground Ns ( Bq Ar window , +.Bq Ar flag ) +.Xc +Move +.Nm window +in or out of foreground. +.Ar Flag +is a boolean value. The old foreground flag +is returned. Default for +.Nm window +is the current window, +default for +.Ar flag +is no change. +.It Xo +.Ic label Ns ( Bq Ar window , +.Bq Ar label ) +.Xc +Set the label of +.Nm window +to +.Ar label . +Returns the old +label as a string. Default for +.Nm window +is the current +window, default for +.Ar label +is no change. To turn +off a label, set it to an empty string (""). +.It Ic list Ns Pq +No arguments. List the identifiers and labels of all windows. No +value is returned. +.It Ic select Ns Pq Bq Ar window +Make +.Nm window +the current window. The previous current window +is returned. Default is no change. +.It Ic source Ns Pq Ar filename +Read and execute the long commands in +.Ar filename . +Returns \-1 if the file cannot be read, 0 otherwise. +.It Ic terse Ns Pq Bq flag +Set terse mode to +.Ar flag . +In terse mode, the command window +stays hidden even in command mode, and errors are reported by +sounding the terminal's bell. +.Ar Flag +can take on the same +values as in +.Ar foreground +above. Returns the old terse flag. +Default is no change. +.It Ic unalias Ns Pq Ar alias +Undefine +.Ar alias . +Returns -1 if +.Ar alias +does not exist, +0 otherwise. +.It Ic unset Ns Pq Ar variable +Undefine +.Ar variable . +Returns -1 if +.Ar variable +does not exist, +0 otherwise. +.It Ic variables Ns Pq +No arguments. List all variables. No value is returned. +.It Xo +.Ic window Ns ( Bq Ar row , +.Bq Ar column , +.Bq Ar nrow , +.Bq Ar ncol , +.Bq Ar nline , +.Bq Ar label , +.Bq Ar pty , +.Bq Ar frame , +.Bq Ar mapnl , +.Bq Ar keepopen , +.Bq Ar smooth , +.Bq Ar shell ) . +.Xc +Open a window with upper left corner at +.Ar row , +.Ar column +and size +.Ar nrow , +.Ar ncol . +If +.Ar nline +is specified, +then that many lines are allocated for the text buffer. Otherwise, +the default buffer size is used. Default values for +.Ar row , +.Ar column , +.Ar nrow , +and +.Ar ncol +are, respectively, +the upper, left-most, lower, or right-most extremes of the +screen. +.Ar Label +is the label string. +.Ar Frame , +.Ar pty , +and +.Ar mapnl +are flag values +interpreted in the same way as the argument to +.Ar foreground +(see above); +they mean, respectively, put a frame around this window (default true), +allocate pseudo-terminal for this window rather than socketpair (default +true), and map new line characters in this window to carriage return +and line feed (default true if socketpair is used, false otherwise). +Normally, a window is automatically closed when its process +exits. Setting +.Ar keepopen +to true (default false) prevents this +action. When +.Ar smooth +is true, the screen is updated more frequently +(for this window) to produce a more terminal-like behavior. +The default value of +.Ar smooth +is set by the +.Ar default_smooth +command (see above). +.Ar Shell +is a list of strings that will be used as the shell +program to place in the window (default is the program specified +by +.Ar default_shell , +see above). The created window's identifier +is returned as a number. +.It Xo +.Ic write Ns ( Bq Ar window , +.Bq Aq Ar string\-list ) +.Xc +Send the list of strings, +.Aq Ar string-list , +to +.Nm window , +separated +by spaces but not terminated with a new line. The strings are actually +given to the window as input. No value is returned. Default +is the current window. +.El +.Ss Predefined Variables +These variables are for information only. Redefining them does +not affect the internal operation of +.Nm window . +.Bl -tag -width modes +.It Ar baud +The baud rate as a number between 50 and 38400. +.It Ar modes +The display modes (reverse video, underline, blinking, graphics) +supported by the physical terminal. The value of +.Ar modes +is the bitwise or of some of the one bit values, +.Ar m_blk , +.Ar m_grp , +.Ar m_rev , +and +.Ar m_ul +(see below). +These values are useful +in setting the window cursors' modes (see +.Ar cursormodes +above). +.It Ar m_blk +The blinking mode bit. +.It Ar m_grp +The graphics mode bit (not very useful). +.It Ar m_rev +The reverse video mode bit. +.It Ar m_ul +The underline mode bit. +.It Ar ncol +The number of columns on the physical screen. +.It Ar nrow +The number of rows on the physical screen. +.It Ar term +The terminal type. The standard name, found in the second name +field of the terminal's +.Ev TERMCAP +entry, is used. +.Sh ENVIRONMENT +.Nm Window +utilizes these environment variables: +.Ev HOME , +.Ev SHELL , +.Ev TERM , +.Ev TERMCAP , +.Ev WINDOW_ID . +.Sh FILES +.Bl -tag -width /dev/[pt]ty[pq]? -compact +.It Pa ~/.windowrc +startup command file. +.It Pa /dev/[pt]ty[pq]? +pseudo-terminal devices. +.El +.Sh HISTORY +The +.Nm window +command appeared in +.Bx 4.3 . +.Sh DIAGNOSTICS +Should be self explanatory. diff --git a/usr.bin/window/windowrc b/usr.bin/window/windowrc new file mode 100644 index 0000000..57c695a --- /dev/null +++ b/usr.bin/window/windowrc @@ -0,0 +1,85 @@ +# Copyright (c) 1983, 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. +# +# @(#)windowrc 8.1 (Berkeley) 6/6/93 +# + +# Configuration file example for window manager +# To be installed in ~/.windowrc +# +# Create two unequal sized windows of full screen width, +# and set up some useful aliases. +# + +# +# Optional settings +# +# terse on # set terse mode +# escape "^A" # set escape character +# nline 100 # set default buffer size + # initially, this is 48 + +# +# Make two windows +# The bottom one is MIN(24, total lines * 3 / 4) lines +# The top one is the rest of the screen. +# +three_fourth = $nrow - ((_ = $nrow * 3 / 4) > 24 ? 24 : $_) +unset _ +window row = 0, nrow = $three_fourth - 1, label = "Top" +window row = $three_fourth, label = "Local" + +# +# Useful aliases +# +# +# Standard window +# +alias std "window r = $three_fourth, l = $?1 ? $1 : ''" +# +# Sysline, add your own options +# +alias sysline "_ = select();" \ + "foreground window(r = 0, nr = 1, nc = $ncol + 1, nl = 0," \ + "l = sysline, pty = no, frame = no, sh = sysline \\-w), 1;" \ + "select $_; unset _" +# +# Rlogin +# +alias rlogin "window r = $three_fourth, l = $1, pty = no, mapnl = no," \ + "sh = sh \\-c 'echo $TERMCAP | rsh ' + $1 + ' \\'cat > .TERMCAP\\' ;" \ + "exec rlogin ' + $1" +alias rl rlogin \$1 +# +# Two equal windows +# +alias two "window r = 1, nr = $nrow / 2 - 1, l = top;" \ + "window r = $nrow / 2 + 1, l = bottom" diff --git a/usr.bin/window/ww.h b/usr.bin/window/ww.h new file mode 100644 index 0000000..9241492 --- /dev/null +++ b/usr.bin/window/ww.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ww.h 8.1 (Berkeley) 6/6/93 + */ + +#ifdef OLD_TTY +#include +#else +#include +#endif +#include +#include + +#define NWW 30 /* maximum number of windows */ + + /* a rectangle */ +struct ww_dim { + int nr; /* number of rows */ + int nc; /* number of columns */ + int t, b; /* top, bottom */ + int l, r; /* left, right */ +}; + + /* a coordinate */ +struct ww_pos { + int r; /* row */ + int c; /* column */ +}; + + /* the window structure */ +struct ww { + /* general flags and states */ + char ww_state; /* state of window */ + char ww_oflags; /* wwopen flags */ + + /* information for overlap */ + struct ww *ww_forw; /* doubly linked list, for overlapping info */ + struct ww *ww_back; + char ww_index; /* the window index, for wwindex[] */ + char ww_order; /* the overlapping order */ + + /* sizes and positions */ + struct ww_dim ww_w; /* window size and pos */ + struct ww_dim ww_b; /* buffer size and pos */ + struct ww_dim ww_i; /* the part inside the screen */ + struct ww_pos ww_cur; /* the cursor position, relative to ww_w */ + + /* arrays */ + char **ww_win; /* the window */ + union ww_char **ww_buf; /* the buffer */ + char **ww_fmap; /* map for frame and box windows */ + short *ww_nvis; /* how many ww_buf chars are visible per row */ + + /* information for wwwrite() and company */ + char ww_wstate; /* state for outputting characters */ + char ww_modes; /* current display modes */ + char ww_insert; /* insert mode */ + char ww_mapnl; /* map \n to \r\n */ + char ww_noupdate; /* don't do updates in wwwrite() */ + char ww_unctrl; /* expand control characters */ + char ww_nointr; /* wwwrite() not interruptable */ + char ww_hascursor; /* has fake cursor */ + + /* things for the window process and io */ + char ww_ispty; /* ww_pty is really a pty, not socket pair */ + char ww_stopped; /* output stopped */ + int ww_pty; /* file descriptor of pty or socket pair */ + int ww_socket; /* other end of socket pair */ + int ww_pid; /* pid of process, if WWS_HASPROC true */ + char ww_ttyname[11]; /* "/dev/ttyp?" */ + char *ww_ob; /* output buffer */ + char *ww_obe; /* end of ww_ob */ + char *ww_obp; /* current read position in ww_ob */ + char *ww_obq; /* current write position in ww_ob */ + + /* things for the user, they really don't belong here */ + char ww_id; /* the user window id */ + char ww_center; /* center the label */ + char ww_hasframe; /* frame it */ + char ww_keepopen; /* keep it open after the process dies */ + char *ww_label; /* the user supplied label */ + struct ww_dim ww_alt; /* alternate position and size */ +}; + + /* state of a tty */ +struct ww_tty { +#ifdef OLD_TTY + struct sgttyb ww_sgttyb; + struct tchars ww_tchars; + struct ltchars ww_ltchars; + int ww_lmode; + int ww_ldisc; +#else + struct termios ww_termios; +#endif + int ww_fflags; +}; + +union ww_char { + short c_w; /* as a word */ + struct { +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + char C_c; /* the character part */ + char C_m; /* the mode part */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + char C_m; /* the mode part */ + char C_c; /* the character part */ +#endif + } c_un; +}; +#define c_c c_un.C_c +#define c_m c_un.C_m + + /* for display update */ +struct ww_update { + int best_gain; + int best_col; + int gain; +}; + + /* parts of ww_char */ +#define WWC_CMASK 0x00ff +#define WWC_MMASK 0xff00 +#define WWC_MSHIFT 8 + + /* c_m bits */ +#define WWM_REV 0x01 /* reverse video */ +#define WWM_BLK 0x02 /* blinking */ +#define WWM_UL 0x04 /* underlined */ +#define WWM_GRP 0x08 /* graphics */ +#define WWM_DIM 0x10 /* half intensity */ +#define WWM_USR 0x20 /* user specified mode */ +#define WWM_GLS 0x40 /* window only, glass, i.e., transparent */ + + /* ww_state values */ +#define WWS_INITIAL 0 /* just opened */ +#define WWS_HASPROC 1 /* has process on pty */ +#define WWS_DEAD 3 /* child died */ + + /* flags for ww_fmap */ +#define WWF_U 0x01 +#define WWF_R 0x02 +#define WWF_D 0x04 +#define WWF_L 0x08 +#define WWF_MASK (WWF_U|WWF_R|WWF_D|WWF_L) +#define WWF_LABEL 0x40 +#define WWF_TOP 0x80 + + /* flags to wwopen() */ +#define WWO_PTY 0x01 /* want pty */ +#define WWO_SOCKET 0x02 /* want socket pair */ +#define WWO_REVERSE 0x04 /* make it all reverse video */ +#define WWO_GLASS 0x08 /* make it all glass */ +#define WWO_FRAME 0x10 /* this is a frame window */ + + /* special ww_index value */ +#define WWX_NOBODY NWW + + /* error codes */ +#define WWE_NOERR 0 +#define WWE_SYS 1 /* system error */ +#define WWE_NOMEM 2 /* out of memory */ +#define WWE_TOOMANY 3 /* too many windows */ +#define WWE_NOPTY 4 /* no more ptys */ +#define WWE_SIZE 5 /* bad window size */ +#define WWE_BADTERM 6 /* bad terminal type */ +#define WWE_CANTDO 7 /* dumb terminal */ + + /* wwtouched[] bits, there used to be more than one */ +#define WWU_TOUCHED 0x01 /* touched */ + + /* the window structures */ +struct ww wwhead; +struct ww *wwindex[NWW + 1]; /* last location is for wwnobody */ +struct ww wwnobody; + + /* tty things */ +struct ww_tty wwoldtty; /* the old (saved) terminal settings */ +struct ww_tty wwnewtty; /* the new (current) terminal settings */ +struct ww_tty wwwintty; /* the terminal settings for windows */ +char *wwterm; /* the terminal name */ +char wwtermcap[1024]; /* place for the termcap */ + + /* generally useful variables */ +int wwnrow, wwncol; /* the screen size */ +char wwavailmodes; /* actually supported modes */ +char wwcursormodes; /* the modes for the fake cursor */ +char wwwrap; /* terminal has auto wrap around */ +int wwdtablesize; /* result of getdtablesize() call */ +char **wwsmap; /* the screen map */ +union ww_char **wwos; /* the old (current) screen */ +union ww_char **wwns; /* the new (desired) screen */ +union ww_char **wwcs; /* the checkpointed screen */ +char *wwtouched; /* wwns changed flags */ +struct ww_update *wwupd; /* for display update */ +int wwospeed; /* output baud rate, copied from wwoldtty */ +int wwbaud; /* wwospeed converted into actual number */ +int wwcursorrow, wwcursorcol; /* where we want the cursor to be */ +int wwerrno; /* error number */ + + /* statistics */ +int wwnflush, wwnwr, wwnwre, wwnwrz, wwnwrc; +int wwnwwr, wwnwwra, wwnwwrc; +int wwntokdef, wwntokuse, wwntokbad, wwntoksave, wwntokc; +int wwnupdate, wwnupdline, wwnupdmiss; +int wwnupdscan, wwnupdclreol, wwnupdclreos, wwnupdclreosmiss, wwnupdclreosline; +int wwnread, wwnreade, wwnreadz; +int wwnreadc, wwnreadack, wwnreadnack, wwnreadstat, wwnreadec; +int wwnwread, wwnwreade, wwnwreadz, wwnwreadd, wwnwreadc, wwnwreadp; +int wwnselect, wwnselecte, wwnselectz; + + /* quicky macros */ +#define wwsetcursor(r,c) (wwcursorrow = (r), wwcursorcol = (c)) +#define wwcurtowin(w) wwsetcursor((w)->ww_cur.r, (w)->ww_cur.c) +#define wwunbox(w) wwunframe(w) +#define wwclreol(w,r,c) wwclreol1((w), (r), (c), 0) +#define wwredrawwin(w) wwredrawwin1((w), (w)->ww_i.t, (w)->ww_i.b, 0) +#define wwupdate() wwupdate1(0, wwnrow); + + /* things for handling input */ +void wwrint(); /* interrupt handler */ +struct ww *wwcurwin; /* window to copy input into */ +char *wwib; /* input (keyboard) buffer */ +char *wwibe; /* wwib + sizeof buffer */ +char *wwibp; /* current read position in buffer */ +char *wwibq; /* current write position in buffer */ +#define wwmaskc(c) ((c) & 0x7f) +#define wwgetc() (wwibp < wwibq ? wwmaskc(*wwibp++) : -1) +#define wwpeekc() (wwibp < wwibq ? wwmaskc(*wwibp) : -1) +#define wwungetc(c) (wwibp > wwib ? *--wwibp = (c) : -1) + + /* things for short circuiting wwiomux() */ +char wwintr; /* interrupting */ +char wwsetjmp; /* want a longjmp() from wwrint() and wwchild() */ +jmp_buf wwjmpbuf; /* jmpbuf for above */ +#define wwinterrupt() wwintr +#define wwsetintr() do { wwintr = 1; if (wwsetjmp) longjmp(wwjmpbuf, 1); } \ + while (0) +#define wwclrintr() (wwintr = 0) + + /* checkpointing */ +int wwdocheckpoint; + + /* the window virtual terminal */ +#define WWT_TERM "window-v2" +#define WWT_TERMCAP "WW|window-v2|window program version 2:\ + :am:bs:da:db:ms:pt:cr=^M:nl=^J:bl=^G:ta=^I:\ + :cm=\\EY%+ %+ :le=^H:nd=\\EC:up=\\EA:do=\\EB:ho=\\EH:\ + :cd=\\EJ:ce=\\EK:cl=\\EE:me=\\Er^?:" +#define WWT_REV "se=\\ErA:so=\\EsA:mr=\\EsA:" +#define WWT_BLK "BE=\\ErB:BS=\\EsB:mb=\\EsB:" +#define WWT_UL "ue=\\ErD:us=\\EsD:" +#define WWT_GRP "ae=\\ErH:as=\\EsH:" +#define WWT_DIM "HE=\\ErP:HS=\\EsP:mh=\\EsP:" +#define WWT_USR "XE=\\Er`:XS=\\Es`:" +#define WWT_ALDL "al=\\EL:dl=\\EM:" +#define WWT_IMEI "im=\\E@:ei=\\EO:ic=:mi:" /* XXX, ic for emacs bug */ +#define WWT_IC "ic=\\EP:" +#define WWT_DC "dc=\\EN:" +char wwwintermcap[1024]; /* terminal-specific but window-independent + part of the window termcap */ +#ifdef TERMINFO + /* where to put the temporary terminfo directory */ +char wwterminfopath[1024]; +#endif + + /* our functions */ +struct ww *wwopen(); +void wwchild(); +void wwalarm(); +void wwquit(); +char **wwalloc(); +char *wwerror(); + + /* c library functions */ +char *malloc(); +char *calloc(); +char *getenv(); +char *tgetstr(); +char *rindex(); +char *strcpy(); +char *strcat(); + +#undef MIN +#undef MAX +#define MIN(x, y) ((x) > (y) ? (y) : (x)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) diff --git a/usr.bin/window/wwadd.c b/usr.bin/window/wwadd.c new file mode 100644 index 0000000..377464a --- /dev/null +++ b/usr.bin/window/wwadd.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwadd.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +/* + * Stick w1 behind w2. + */ +wwadd(w1, w2) +register struct ww *w1; +struct ww *w2; +{ + register i; + register struct ww *w; + + w1->ww_order = w2->ww_order + 1; + w1->ww_back = w2; + w1->ww_forw = w2->ww_forw; + w2->ww_forw->ww_back = w1; + w2->ww_forw = w1; + + for (w = w1->ww_forw; w != &wwhead; w = w->ww_forw) + w->ww_order++; + for (i = w1->ww_i.t; i < w1->ww_i.b; i++) { + register j; + register char *smap = wwsmap[i]; + register char *win = w1->ww_win[i]; + union ww_char *ns = wwns[i]; + union ww_char *buf = w1->ww_buf[i]; + int nvis = 0; + int nchanged = 0; + + for (j = w1->ww_i.l; j < w1->ww_i.r; j++) { + w = wwindex[smap[j]]; + if (w1->ww_order > w->ww_order) + continue; + if (win[j] & WWM_GLS) + continue; + if (w != &wwnobody && w->ww_win[i][j] == 0) + w->ww_nvis[i]--; + smap[j] = w1->ww_index; + if (win[j] == 0) + nvis++; + ns[j].c_w = buf[j].c_w ^ win[j] << WWC_MSHIFT; + nchanged++; + } + if (nchanged > 0) + wwtouched[i] |= WWU_TOUCHED; + w1->ww_nvis[i] = nvis; + } +} diff --git a/usr.bin/window/wwalloc.c b/usr.bin/window/wwalloc.c new file mode 100644 index 0000000..009bf12 --- /dev/null +++ b/usr.bin/window/wwalloc.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwalloc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +char ** +wwalloc(row, col, nrow, ncol, size) +{ + register char *p, **pp; + register int i; + + /* fast, call malloc only once */ + pp = (char **) + malloc((unsigned) sizeof (char **) * nrow + size * nrow * ncol); + if (pp == 0) { + wwerrno = WWE_NOMEM; + return 0; + } + p = (char *)&pp[nrow]; + col *= size; + size /= sizeof (char); /* paranoid */ + size *= ncol; + for (i = 0; i < nrow; i++) { + pp[i] = p - col; + p += size; + } + return pp - row; +} + +wwfree(p, row) +register char **p; +{ + free((char *)(p + row)); +} diff --git a/usr.bin/window/wwbox.c b/usr.bin/window/wwbox.c new file mode 100644 index 0000000..f4dd52b --- /dev/null +++ b/usr.bin/window/wwbox.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwbox.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwbox(w, r, c, nr, nc) +register struct ww *w; +register r, c; +int nr, nc; +{ + register r1, c1; + register i; + + r1 = r + nr - 1; + c1 = c + nc - 1; + wwframec(w, r, c, WWF_D|WWF_R); + for (i = c + 1; i < c1; i++) + wwframec(w, r, i, WWF_L|WWF_R); + wwframec(w, r, i, WWF_L|WWF_D); + for (i = r + 1; i < r1; i++) + wwframec(w, i, c1, WWF_U|WWF_D); + wwframec(w, i, c1, WWF_U|WWF_L); + for (i = c1 - 1; i > c; i--) + wwframec(w, r1, i, WWF_R|WWF_L); + wwframec(w, r1, i, WWF_R|WWF_U); + for (i = r1 - 1; i > r; i--) + wwframec(w, i, c, WWF_D|WWF_U); +} diff --git a/usr.bin/window/wwchild.c b/usr.bin/window/wwchild.c new file mode 100644 index 0000000..944bdd9 --- /dev/null +++ b/usr.bin/window/wwchild.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwchild.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include +#include + +void +wwchild() +{ + extern errno; + int olderrno; + register struct ww **wp; + union wait w; + int pid; + char collected = 0; + + olderrno = errno; + while ((pid = + wait3((int *)&w, WNOHANG|WUNTRACED, (struct rusage *)0)) > 0) { + for (wp = wwindex; wp < &wwindex[NWW]; wp++) { + if (*wp && (*wp)->ww_state == WWS_HASPROC + && (*wp)->ww_pid == pid) { + (*wp)->ww_state = WWS_DEAD; + collected = 1; + break; + } + } + } + errno = olderrno; + /* jump out of wwiomux when somebody dies */ + if (collected) + wwsetintr(); +} diff --git a/usr.bin/window/wwclose.c b/usr.bin/window/wwclose.c new file mode 100644 index 0000000..a27aed9 --- /dev/null +++ b/usr.bin/window/wwclose.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwclose.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwclose(w) +register struct ww *w; +{ + wwindex[w->ww_index] = 0; + if (w->ww_pty >= 0) + (void) close(w->ww_pty); + if (w->ww_socket >= 0) + (void) close(w->ww_socket); + wwfree((char **)w->ww_win, w->ww_w.t); + wwfree((char **)w->ww_buf, w->ww_b.t); + if (w->ww_fmap != 0) + wwfree((char **)w->ww_fmap, w->ww_w.t); + free((char *)(w->ww_nvis + w->ww_w.t)); + if (w->ww_ob != 0) + free(w->ww_ob); + free((char *)w); +} diff --git a/usr.bin/window/wwclreol.c b/usr.bin/window/wwclreol.c new file mode 100644 index 0000000..d827f67 --- /dev/null +++ b/usr.bin/window/wwclreol.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwclreol.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +/* + * Clear w to the end of line. + * If cleared is true, then the screen line has already been cleared. + */ +wwclreol1(w, row, col, cleared) +register struct ww *w; +int row, col; +char cleared; +{ + register i; + + /* + * Clear the buffer right off + */ + { + register union ww_char *buf; + + buf = &w->ww_buf[row][col]; + for (i = w->ww_b.r - col; --i >= 0;) + buf++->c_w = ' '; + } + + /* + * If can't see it, just return. + */ + if (row < w->ww_i.t || row >= w->ww_i.b + || w->ww_i.r <= 0 || w->ww_i.r <= col) + return; + + if (col < w->ww_i.l) + col = w->ww_i.l; + + /* + * Now fix wwns. + */ + { + register union ww_char *s; + register char *smap, *win; + + i = col; + smap = &wwsmap[row][i]; + s = &wwns[row][i]; + win = &w->ww_win[row][i]; + for (i = w->ww_i.r - i; --i >= 0;) + if (*smap++ == w->ww_index) + s++->c_w = ' ' | *win++ << WWC_MSHIFT; + else + s++, win++; + } + if (!cleared) + wwtouched[row] |= WWU_TOUCHED; +} diff --git a/usr.bin/window/wwclreos.c b/usr.bin/window/wwclreos.c new file mode 100644 index 0000000..f3d462c --- /dev/null +++ b/usr.bin/window/wwclreos.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwclreos.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwclreos(w, row, col) +register struct ww *w; +{ + register i; + + wwclreol(w, row, col); + for (i = row + 1; i < w->ww_b.b; i++) + wwclreol(w, i, w->ww_b.l); + /* XXX */ + if (!w->ww_noupdate) + wwupdate1(w->ww_i.t, w->ww_i.b); +} diff --git a/usr.bin/window/wwcursor.c b/usr.bin/window/wwcursor.c new file mode 100644 index 0000000..cd9cdba --- /dev/null +++ b/usr.bin/window/wwcursor.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwcursor.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwcursor(w, on) +register struct ww *w; +{ + register char *win; + + if (on) { + if (w->ww_hascursor) + return; + w->ww_hascursor = 1; + } else { + if (!w->ww_hascursor) + return; + w->ww_hascursor = 0; + } + if (wwcursormodes != 0) { + win = &w->ww_win[w->ww_cur.r][w->ww_cur.c]; + *win ^= wwcursormodes; + if (w->ww_cur.r < w->ww_i.t || w->ww_cur.r >= w->ww_i.b + || w->ww_cur.c < w->ww_i.l || w->ww_cur.c >= w->ww_i.r) + return; + if (wwsmap[w->ww_cur.r][w->ww_cur.c] == w->ww_index) { + if (*win == 0) + w->ww_nvis[w->ww_cur.r]++; + else if (*win == wwcursormodes) + w->ww_nvis[w->ww_cur.r]--; + wwns[w->ww_cur.r][w->ww_cur.c].c_m ^= wwcursormodes; + wwtouched[w->ww_cur.r] |= WWU_TOUCHED; + } + } +} + +wwsetcursormodes(new) +register new; +{ + register i; + register struct ww *w; + register old = wwcursormodes; + + new &= wwavailmodes; + if (new == wwcursormodes) + return; + for (i = 0; i < NWW; i++) + if (wwindex[i] != 0 && (w = wwindex[i])->ww_hascursor) { + wwcursor(w, 0); + wwcursormodes = new; + wwcursor(w, 1); + wwcursormodes = old; + } + wwcursormodes = new; +} diff --git a/usr.bin/window/wwdata.c b/usr.bin/window/wwdata.c new file mode 100644 index 0000000..1280589 --- /dev/null +++ b/usr.bin/window/wwdata.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwdata.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ diff --git a/usr.bin/window/wwdelchar.c b/usr.bin/window/wwdelchar.c new file mode 100644 index 0000000..cd58833 --- /dev/null +++ b/usr.bin/window/wwdelchar.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwdelchar.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwdelchar(w, row, col) +register struct ww *w; +{ + register i; + int nvis; + + /* + * First, shift the line. + */ + { + register union ww_char *p, *q; + + p = &w->ww_buf[row][col]; + q = p + 1; + for (i = w->ww_b.r - col; --i > 0;) + *p++ = *q++; + p->c_w = ' '; + } + + /* + * If can't see it, just return. + */ + if (row < w->ww_i.t || row >= w->ww_i.b + || w->ww_i.r <= 0 || w->ww_i.r <= col) + return; + + if (col < w->ww_i.l) + col = w->ww_i.l; + + /* + * Now find out how much is actually changed, and fix wwns. + */ + { + register union ww_char *buf; + register char *win; + register union ww_char *ns; + register char *smap; + char touched; + + nvis = 0; + smap = &wwsmap[row][col]; + for (i = col; i < w->ww_i.r && *smap++ != w->ww_index; i++) + ; + if (i >= w->ww_i.r) + return; + col = i; + buf = w->ww_buf[row]; + win = w->ww_win[row]; + ns = wwns[row]; + smap = &wwsmap[row][i]; + touched = wwtouched[row]; + for (; i < w->ww_i.r; i++) { + if (*smap++ != w->ww_index) + continue; + touched |= WWU_TOUCHED; + if (win[i]) + ns[i].c_w = + buf[i].c_w ^ win[i] << WWC_MSHIFT; + else { + nvis++; + ns[i] = buf[i]; + } + } + wwtouched[row] = touched; + } + + /* + * Can/Should we use delete character? + */ + if (tt.tt_delchar != 0 && nvis > (wwncol - col) / 2) { + register union ww_char *p, *q; + + xxdelchar(row, col); + p = &wwos[row][col]; + q = p + 1; + for (i = wwncol - col; --i > 0;) + *p++ = *q++; + p->c_w = ' '; + } +} diff --git a/usr.bin/window/wwdelete.c b/usr.bin/window/wwdelete.c new file mode 100644 index 0000000..f659736 --- /dev/null +++ b/usr.bin/window/wwdelete.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwdelete.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +/* + * Pull w free from the cover list. + */ +wwdelete(w) +register struct ww *w; +{ + register i; + + for (i = w->ww_i.t; i < w->ww_i.b; i++) { + register j; + register char *smap = wwsmap[i]; + register union ww_char *ns = wwns[i]; + register int nchanged = 0; + + for (j = w->ww_i.l; j < w->ww_i.r; j++) + if (smap[j] == w->ww_index) { + smap[j] = WWX_NOBODY; + ns[j].c_w = ' '; + nchanged++; + } + if (nchanged > 0) + wwtouched[i] |= WWU_TOUCHED; + } + + { + register struct ww *wp; + + for (wp = w->ww_forw; wp != &wwhead; wp = wp->ww_forw) + wp->ww_order--; + } + + if (w->ww_forw != &wwhead) + wwdelete1(w->ww_forw, + w->ww_i.t, w->ww_i.b, w->ww_i.l, w->ww_i.r); + + w->ww_back->ww_forw = w->ww_forw; + w->ww_forw->ww_back = w->ww_back; + w->ww_forw = w->ww_back = 0; +} + +wwdelete1(w, t, b, l, r) +register struct ww *w; +{ + int i; + int tt, bb, ll, rr; + char hasglass; + +again: + hasglass = 0; + tt = MAX(t, w->ww_i.t); + bb = MIN(b, w->ww_i.b); + ll = MAX(l, w->ww_i.l); + rr = MIN(r, w->ww_i.r); + if (tt >= bb || ll >= rr) { + if ((w = w->ww_forw) == &wwhead) + return; + goto again; + } + for (i = tt; i < bb; i++) { + register j; + register char *smap = wwsmap[i]; + register union ww_char *ns = wwns[i]; + register char *win = w->ww_win[i]; + register union ww_char *buf = w->ww_buf[i]; + int nvis = w->ww_nvis[i]; + int nchanged = 0; + + for (j = ll; j < rr; j++) { + if (smap[j] != WWX_NOBODY) + continue; + if (win[j] & WWM_GLS) { + hasglass = 1; + continue; + } + smap[j] = w->ww_index; + ns[j].c_w = buf[j].c_w ^ win[j] << WWC_MSHIFT; + nchanged++; + if (win[j] == 0) + nvis++; + } + if (nchanged > 0) + wwtouched[i] |= WWU_TOUCHED; + w->ww_nvis[i] = nvis; + } + if ((w = w->ww_forw) == &wwhead) + return; + if (hasglass) + goto again; + if (tt > t) + wwdelete1(w, t, tt, l, r); + if (bb < b) + wwdelete1(w, bb, b, l, r); + if (ll > l) + wwdelete1(w, tt, bb, l, ll); + if (rr < r) + wwdelete1(w, tt, bb, rr, r); +} diff --git a/usr.bin/window/wwdelline.c b/usr.bin/window/wwdelline.c new file mode 100644 index 0000000..f2aef72 --- /dev/null +++ b/usr.bin/window/wwdelline.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwdelline.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwdelline(w, row) +register struct ww *w; +int row; +{ + register i; + register union ww_char **cpp, **cqq; + register union ww_char *cp; + int row1, row2; + char deleted; + int visible; + + /* + * Scroll first. + */ + if ((row1 = row) < w->ww_i.t) { + row1 = w->ww_i.t; + } + if ((row2 = w->ww_b.b) > w->ww_i.b) { + row2 = w->ww_i.b; + visible = 0; + } else + visible = 1; + deleted = wwscroll1(w, row1, row2, 1, visible); + + /* + * Fix the buffer. + * But leave clearing the last line for wwclreol(). + */ + cpp = &w->ww_buf[row]; + cqq = cpp + 1; + cp = *cpp; + for (i = w->ww_b.b - row; --i > 0;) + *cpp++ = *cqq++; + *cpp = cp; + + /* + * Now clear the last line. + */ + if (visible) + wwclreol1(w, w->ww_b.b - 1, w->ww_b.l, deleted); + else { + cp += w->ww_b.l; + for (i = w->ww_b.nc; --i >= 0;) + cp++->c_w = ' '; + } +} diff --git a/usr.bin/window/wwdump.c b/usr.bin/window/wwdump.c new file mode 100644 index 0000000..8f60d4e --- /dev/null +++ b/usr.bin/window/wwdump.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwdump.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +static char cmap[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +wwdumpwin(w) +register struct ww *w; +{ + register i, j; + + tt.tt_nmodes = 0; + (*tt.tt_clear)(); + for (i = w->ww_i.t; i < w->ww_i.b; i++) { + (*tt.tt_move)(i, w->ww_i.l); + for (j = w->ww_i.l; j < w->ww_i.r; j++) + (*tt.tt_putc)(w->ww_win[i][j] & WWM_GLS ? 'G' : ' '); + } +} + +wwdumpnvis(w) +register struct ww *w; +{ + register i; + char buf[20]; + + tt.tt_nmodes = 0; + (*tt.tt_clear)(); + for (i = w->ww_i.t; i < w->ww_i.b; i++) { + (*tt.tt_move)(i, w->ww_i.l); + (void) sprintf(buf, "%d", w->ww_nvis[i]); + (*tt.tt_write)(buf, strlen(buf)); + } +} + +wwdumpsmap() +{ + register i, j; + + tt.tt_nmodes = 0; + (*tt.tt_clear)(); + for (i = 0; i < wwnrow; i++) { + (*tt.tt_move)(i, 0); + for (j = 0; j < wwncol; j++) + (*tt.tt_putc)(cmap[wwsmap[i][j]]); + } +} + +wwdumpns() +{ + register i, j; + + (*tt.tt_clear)(); + for (i = 0; i < wwnrow; i++) { + (*tt.tt_move)(i, 0); + for (j = 0; j < wwncol; j++) { + tt.tt_nmodes = wwns[i][j].c_m & tt.tt_availmodes; + (*tt.tt_putc)(wwns[i][j].c_c); + } + } +} + +wwdumpos() +{ + register i, j; + + (*tt.tt_clear)(); + for (i = 0; i < wwnrow; i++) { + (*tt.tt_move)(i, 0); + for (j = 0; j < wwncol; j++) { + tt.tt_nmodes = wwos[i][j].c_m & tt.tt_availmodes; + (*tt.tt_putc)(wwns[i][j].c_c); + } + } +} diff --git a/usr.bin/window/wwend.c b/usr.bin/window/wwend.c new file mode 100644 index 0000000..9586f14 --- /dev/null +++ b/usr.bin/window/wwend.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwend.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +/*ARGSUSED*/ +wwend(exit) +{ + if (tt.tt_checkpoint) { + (void) alarm(0); + wwdocheckpoint = 0; + } + xxend(); + (void) wwsettty(0, &wwoldtty); +#ifdef TERMINFO + if (exit) + wwterminfoend(); +#endif +} + +void +wwquit() +{ + wwend(1); + exit(1); +} diff --git a/usr.bin/window/wwenviron.c b/usr.bin/window/wwenviron.c new file mode 100644 index 0000000..2b5d82c --- /dev/null +++ b/usr.bin/window/wwenviron.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwenviron.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#if !defined(OLD_TTY) && !defined(TIOCSCTTY) && !defined(TIOCNOTTY) +#include +#endif +#include + +/* + * Set up the environment of this process to run in window 'wp'. + */ +wwenviron(wp) +register struct ww *wp; +{ + register i; +#ifndef TIOCSCTTY + int pgrp = getpid(); +#endif + char buf[1024]; + +#ifndef TIOCSCTTY + if ((i = open("/dev/tty", 0)) < 0) + goto bad; + if (ioctl(i, TIOCNOTTY, (char *)0) < 0) + goto bad; + (void) close(i); +#endif + if ((i = wp->ww_socket) < 0) { + if ((i = open(wp->ww_ttyname, 2)) < 0) + goto bad; + if (wwsettty(i, &wwwintty) < 0) + goto bad; + if (wwsetttysize(i, wp->ww_w.nr, wp->ww_w.nc) < 0) + goto bad; + } + (void) dup2(i, 0); + (void) dup2(i, 1); + (void) dup2(i, 2); + (void) close(i); +#ifdef TIOCSCTTY + (void) setsid(); + (void) ioctl(0, TIOCSCTTY, 0); +#else + (void) ioctl(0, TIOCSPGRP, (char *)&pgrp); + (void) setpgrp(pgrp, pgrp); +#endif + /* SIGPIPE is the only one we ignore */ + (void) signal(SIGPIPE, SIG_DFL); + (void) sigsetmask(0); + /* + * Two conditions that make destructive setenv ok: + * 1. setenv() copies the string, + * 2. we've already called tgetent which copies the termcap entry. + */ + (void) sprintf(buf, "%sco#%d:li#%d:%s", + WWT_TERMCAP, wp->ww_w.nc, wp->ww_w.nr, wwwintermcap); + (void) setenv("TERMCAP", buf, 1); + (void) sprintf(buf, "%d", wp->ww_id + 1); + (void) setenv("WINDOW_ID", buf, 1); + return 0; +bad: + wwerrno = WWE_SYS; + return -1; +} diff --git a/usr.bin/window/wwerror.c b/usr.bin/window/wwerror.c new file mode 100644 index 0000000..0bba6f5 --- /dev/null +++ b/usr.bin/window/wwerror.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwerror.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +char * +wwerror() +{ + extern int errno; + char *strerror(); + + switch (wwerrno) { + case WWE_NOERR: + return "No error"; + case WWE_SYS: + return strerror(errno); + case WWE_NOMEM: + return "Out of memory"; + case WWE_TOOMANY: + return "Too many windows"; + case WWE_NOPTY: + return "Out of pseudo-terminals"; + case WWE_SIZE: + return "Bad window size"; + case WWE_BADTERM: + return "Unknown terminal type"; + case WWE_CANTDO: + return "Can't run window on this terminal"; + default: + return "Unknown error"; + } +} diff --git a/usr.bin/window/wwflush.c b/usr.bin/window/wwflush.c new file mode 100644 index 0000000..1346e56 --- /dev/null +++ b/usr.bin/window/wwflush.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwflush.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include + +wwflush() +{ + register row, col; + + if ((row = wwcursorrow) < 0) + row = 0; + else if (row >= wwnrow) + row = wwnrow - 1; + if ((col = wwcursorcol) < 0) + col = 0; + else if (col >= wwncol) + col = wwncol - 1; + xxmove(row, col); + if (wwdocheckpoint) { + xxflush(0); + wwcheckpoint(); + } else + xxflush(1); +} + +wwcheckpoint() +{ + int s = sigblock(sigmask(SIGALRM) | sigmask(SIGIO)); + + tt.tt_ack = 0; + do { + (*tt.tt_checkpoint)(); +#ifndef OLD_TTY + (void) tcdrain(1); +#endif + (void) alarm(3); + for (wwdocheckpoint = 0; !wwdocheckpoint && tt.tt_ack == 0;) + (void) sigpause(s); + } while (tt.tt_ack == 0); + (void) alarm(0); + wwdocheckpoint = 0; + if (tt.tt_ack < 0) { + wwcopyscreen(wwcs, wwos); + (void) alarm(1); + wwreset(); + wwupdate(); + wwflush(); + } else { + wwcopyscreen(wwos, wwcs); + (void) alarm(3); + } + (void) sigsetmask(s); +} + +wwcopyscreen(s1, s2) + register union ww_char **s1, **s2; +{ + register i; + register s = wwncol * sizeof **s1; + + for (i = wwnrow; --i >= 0;) + bcopy((char *) *s1++, (char *) *s2++, s); +} + +void +wwalarm() +{ + wwdocheckpoint = 1; +} diff --git a/usr.bin/window/wwframe.c b/usr.bin/window/wwframe.c new file mode 100644 index 0000000..bb0badd --- /dev/null +++ b/usr.bin/window/wwframe.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwframe.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +#define frameok(w, r, c) (w1 = wwindex[wwsmap[r][c]], \ + w1->ww_fmap || w1->ww_order > (w)->ww_order) + +wwframe(w, wframe) +register struct ww *w; +struct ww *wframe; +{ + register r, c; + char a1, a2, a3; + char b1, b2, b3; + register char *smap; + register code; + register struct ww *w1; + + if (w->ww_w.t > 0) { + r = w->ww_w.t - 1; + c = w->ww_i.l - 1; + smap = &wwsmap[r + 1][c + 1]; + a1 = 0; + a2 = 0; + b1 = 0; + b2 = c < 0 || frameok(w, r, c); + + for (; c < w->ww_i.r; c++) { + if (c + 1 >= wwncol) { + a3 = 1; + b3 = 1; + } else { + a3 = w->ww_index == *smap++; + b3 = frameok(w, r, c + 1); + } + if (b2) { + code = 0; + if ((a1 || a2) && b1) + code |= WWF_L; + if ((a2 || a3) && b3) + code |= WWF_R; + if (code) + wwframec(wframe, r, c, code|WWF_TOP); + } + a1 = a2; + a2 = a3; + b1 = b2; + b2 = b3; + } + if ((a1 || a2) && b1 && b2) + wwframec(wframe, r, c, WWF_L|WWF_TOP); + } + + if (w->ww_w.b < wwnrow) { + r = w->ww_w.b; + c = w->ww_i.l - 1; + smap = &wwsmap[r - 1][c + 1]; + a1 = 0; + a2 = 0; + b1 = 0; + b2 = c < 0 || frameok(w, r, c); + + for (; c < w->ww_i.r; c++) { + if (c + 1 >= wwncol) { + a3 = 1; + b3 = 1; + } else { + a3 = w->ww_index == *smap++; + b3 = frameok(w, r, c + 1); + } + if (b2) { + code = 0; + if ((a1 || a2) && b1) + code |= WWF_L; + if ((a2 || a3) && b3) + code |= WWF_R; + if (code) + wwframec(wframe, r, c, code); + } + a1 = a2; + a2 = a3; + b1 = b2; + b2 = b3; + } + if ((a1 || a2) && b1 && b2) + wwframec(wframe, r, c, WWF_L); + } + + if (w->ww_w.l > 0) { + r = w->ww_i.t - 1; + c = w->ww_w.l - 1; + a1 = 0; + a2 = 0; + b1 = 0; + b2 = r < 0 || frameok(w, r, c); + + for (; r < w->ww_i.b; r++) { + if (r + 1 >= wwnrow) { + a3 = 1; + b3 = 1; + } else { + a3 = w->ww_index == wwsmap[r + 1][c + 1]; + b3 = frameok(w, r + 1, c); + } + if (b2) { + code = 0; + if ((a1 || a2) && b1) + code |= WWF_U; + if ((a2 || a3) && b3) + code |= WWF_D; + if (code) + wwframec(wframe, r, c, code); + } + a1 = a2; + a2 = a3; + b1 = b2; + b2 = b3; + } + if ((a1 || a2) && b1 && b2) + wwframec(wframe, r, c, WWF_U); + } + + if (w->ww_w.r < wwncol) { + r = w->ww_i.t - 1; + c = w->ww_w.r; + a1 = 0; + a2 = 0; + b1 = 0; + b2 = r < 0 || frameok(w, r, c); + + for (; r < w->ww_i.b; r++) { + if (r + 1 >= wwnrow) { + a3 = 1; + b3 = 1; + } else { + a3 = w->ww_index == wwsmap[r + 1][c - 1]; + b3 = frameok(w, r + 1, c); + } + if (b2) { + code = 0; + if ((a1 || a2) && b1) + code |= WWF_U; + if ((a2 || a3) && b3) + code |= WWF_D; + if (code) + wwframec(wframe, r, c, code); + } + a1 = a2; + a2 = a3; + b1 = b2; + b2 = b3; + } + if ((a1 || a2) && b1 && b2) + wwframec(wframe, r, c, WWF_U); + } +} + +wwframec(f, r, c, code) +register struct ww *f; +register r, c; +char code; +{ + char oldcode; + register char *smap; + + if (r < f->ww_i.t || r >= f->ww_i.b || c < f->ww_i.l || c >= f->ww_i.r) + return; + + smap = &wwsmap[r][c]; + + { + register struct ww *w; + + w = wwindex[*smap]; + if (w->ww_order > f->ww_order) { + if (w != &wwnobody && w->ww_win[r][c] == 0) + w->ww_nvis[r]--; + *smap = f->ww_index; + } + } + + if (f->ww_fmap != 0) { + register char *fmap; + + fmap = &f->ww_fmap[r][c]; + oldcode = *fmap; + *fmap |= code; + if (code & WWF_TOP) + *fmap &= ~WWF_LABEL; + code = *fmap; + } else + oldcode = 0; + { + register char *win = &f->ww_win[r][c]; + + if (*win == WWM_GLS && *smap == f->ww_index) + f->ww_nvis[r]++; + *win &= ~WWM_GLS; + } + if (oldcode != code && (code & WWF_LABEL) == 0) { + register short frame; + + frame = tt.tt_frame[code & WWF_MASK]; + f->ww_buf[r][c].c_w = frame; + if (wwsmap[r][c] == f->ww_index) { + wwtouched[r] |= WWU_TOUCHED; + wwns[r][c].c_w = frame; + } + } +} diff --git a/usr.bin/window/wwgets.c b/usr.bin/window/wwgets.c new file mode 100644 index 0000000..1f69fa5 --- /dev/null +++ b/usr.bin/window/wwgets.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwgets.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "char.h" + +wwgets(buf, n, w) +char *buf; +int n; +register struct ww *w; +{ + register char *p = buf; + register char c; + char uc = w->ww_unctrl; + static void rub(); + + w->ww_unctrl = 0; + for (;;) { + wwcurtowin(w); + while ((c = wwgetc()) < 0) + wwiomux(); +#ifdef OLD_TTY + if (c == wwoldtty.ww_sgttyb.sg_erase) +#else + if (c == wwoldtty.ww_termios.c_cc[VERASE]) +#endif + { + if (p > buf) + rub(*--p, w); + } else +#ifdef OLD_TTY + if (c == wwoldtty.ww_sgttyb.sg_kill) +#else + if (c == wwoldtty.ww_termios.c_cc[VKILL]) +#endif + { + while (p > buf) + rub(*--p, w); + } else +#ifdef OLD_TTY + if (c == wwoldtty.ww_ltchars.t_werasc) +#else + if (c == wwoldtty.ww_termios.c_cc[VWERASE]) +#endif + { + while (--p >= buf && (*p == ' ' || *p == '\t')) + rub(*p, w); + while (p >= buf && *p != ' ' && *p != '\t') + rub(*p--, w); + p++; + } else if (c == '\r' || c == '\n') { + break; + } else { + if (p >= buf + n - 1) + wwputc(ctrl('g'), w); + else + wwputs(unctrl(*p++ = c), w); + } + } + *p = 0; + w->ww_unctrl = uc; +} + +static void +rub(c, w) +struct ww *w; +{ + register i; + + for (i = strlen(unctrl(c)); --i >= 0;) + (void) wwwrite(w, "\b \b", 3); +} diff --git a/usr.bin/window/wwinit.c b/usr.bin/window/wwinit.c new file mode 100644 index 0000000..0581126 --- /dev/null +++ b/usr.bin/window/wwinit.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwinit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include +#include +#include "char.h" + +wwinit() +{ + register i, j; + char *kp; + int s; + + wwdtablesize = getdtablesize(); + wwhead.ww_forw = &wwhead; + wwhead.ww_back = &wwhead; + + s = sigblock(sigmask(SIGIO) | sigmask(SIGCHLD) | sigmask(SIGALRM) | + sigmask(SIGHUP) | sigmask(SIGTERM)); + if (signal(SIGIO, wwrint) == BADSIG || + signal(SIGCHLD, wwchild) == BADSIG || + signal(SIGHUP, wwquit) == BADSIG || + signal(SIGTERM, wwquit) == BADSIG || + signal(SIGPIPE, SIG_IGN) == BADSIG) { + wwerrno = WWE_SYS; + return -1; + } + + if (wwgettty(0, &wwoldtty) < 0) + return -1; + wwwintty = wwoldtty; +#ifdef OLD_TTY + wwwintty.ww_sgttyb.sg_flags &= ~XTABS; + wwnewtty.ww_sgttyb = wwoldtty.ww_sgttyb; + wwnewtty.ww_sgttyb.sg_erase = -1; + wwnewtty.ww_sgttyb.sg_kill = -1; + wwnewtty.ww_sgttyb.sg_flags |= CBREAK; + wwnewtty.ww_sgttyb.sg_flags &= ~(ECHO|CRMOD); + wwnewtty.ww_tchars.t_intrc = -1; + wwnewtty.ww_tchars.t_quitc = -1; + wwnewtty.ww_tchars.t_startc = -1; + wwnewtty.ww_tchars.t_stopc = -1; + wwnewtty.ww_tchars.t_eofc = -1; + wwnewtty.ww_tchars.t_brkc = -1; + wwnewtty.ww_ltchars.t_suspc = -1; + wwnewtty.ww_ltchars.t_dsuspc = -1; + wwnewtty.ww_ltchars.t_rprntc = -1; + wwnewtty.ww_ltchars.t_flushc = -1; + wwnewtty.ww_ltchars.t_werasc = -1; + wwnewtty.ww_ltchars.t_lnextc = -1; + wwnewtty.ww_lmode = wwoldtty.ww_lmode | LLITOUT; + wwnewtty.ww_ldisc = wwoldtty.ww_ldisc; +#else +#ifndef OXTABS +#define OXTABS XTABS +#endif +#ifndef _POSIX_VDISABLE +#define _POSIX_VDISABLE -1 +#endif + wwwintty.ww_termios.c_oflag &= ~OXTABS; + wwnewtty.ww_termios = wwoldtty.ww_termios; + wwnewtty.ww_termios.c_iflag &= + ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IMAXBEL); + wwnewtty.ww_termios.c_oflag = 0; + wwnewtty.ww_termios.c_cflag &= ~(CSIZE | PARENB); + wwnewtty.ww_termios.c_cflag |= CS8; + wwnewtty.ww_termios.c_lflag = 0; + for (i = 0; i < NCCS; i++) + wwnewtty.ww_termios.c_cc[i] = _POSIX_VDISABLE; + wwnewtty.ww_termios.c_cc[VMIN] = 0; + wwnewtty.ww_termios.c_cc[VTIME] = 0; +#endif + wwnewtty.ww_fflags = wwoldtty.ww_fflags | FASYNC; + if (wwsettty(0, &wwnewtty) < 0) + goto bad; + + if ((wwterm = getenv("TERM")) == 0) { + wwerrno = WWE_BADTERM; + goto bad; + } + if (tgetent(wwtermcap, wwterm) != 1) { + wwerrno = WWE_BADTERM; + goto bad; + } +#ifdef OLD_TTY + wwospeed = wwoldtty.ww_sgttyb.sg_ospeed; +#else + wwospeed = cfgetospeed(&wwoldtty.ww_termios); +#endif + switch (wwospeed) { + default: + case B0: + wwbaud = 0; + break; + case B50: + wwbaud = 50; + break; + case B75: + wwbaud = 75; + break; + case B110: + wwbaud = 110; + break; + case B134: + wwbaud = 134; + break; + case B150: + wwbaud = 150; + break; + case B200: + wwbaud = 200; + break; + case B300: + wwbaud = 300; + break; + case B600: + wwbaud = 600; + break; + case B1200: + wwbaud = 1200; + break; + case B1800: + wwbaud = 1800; + break; + case B2400: + wwbaud = 2400; + break; + case B4800: + wwbaud = 4800; + break; + case B9600: + wwbaud = 9600; + break; +#ifdef B19200 + case B19200: +#else + case EXTA: +#endif + wwbaud = 19200; + break; +#ifdef B38400 + case B38400: +#else + case EXTB: +#endif + wwbaud = 38400; + break; + } + + if (xxinit() < 0) + goto bad; + wwnrow = tt.tt_nrow; + wwncol = tt.tt_ncol; + wwavailmodes = tt.tt_availmodes; + wwwrap = tt.tt_wrap; + + if (wwavailmodes & WWM_REV) + wwcursormodes = WWM_REV | wwavailmodes & WWM_BLK; + else if (wwavailmodes & WWM_UL) + wwcursormodes = WWM_UL; + + if ((wwib = malloc((unsigned) 512)) == 0) + goto bad; + wwibe = wwib + 512; + wwibq = wwibp = wwib; + + if ((wwsmap = wwalloc(0, 0, wwnrow, wwncol, sizeof (char))) == 0) + goto bad; + for (i = 0; i < wwnrow; i++) + for (j = 0; j < wwncol; j++) + wwsmap[i][j] = WWX_NOBODY; + + wwos = (union ww_char **) + wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char)); + if (wwos == 0) + goto bad; + /* wwos is cleared in wwstart1() */ + wwns = (union ww_char **) + wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char)); + if (wwns == 0) + goto bad; + for (i = 0; i < wwnrow; i++) + for (j = 0; j < wwncol; j++) + wwns[i][j].c_w = ' '; + if (tt.tt_checkpoint) { + /* wwcs is also cleared in wwstart1() */ + wwcs = (union ww_char **) + wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char)); + if (wwcs == 0) + goto bad; + } + + wwtouched = malloc((unsigned) wwnrow); + if (wwtouched == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + for (i = 0; i < wwnrow; i++) + wwtouched[i] = 0; + + wwupd = (struct ww_update *) malloc((unsigned) wwnrow * sizeof *wwupd); + if (wwupd == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + + wwindex[WWX_NOBODY] = &wwnobody; + wwnobody.ww_order = NWW; + + kp = wwwintermcap; + if (wwavailmodes & WWM_REV) + wwaddcap1(WWT_REV, &kp); + if (wwavailmodes & WWM_BLK) + wwaddcap1(WWT_BLK, &kp); + if (wwavailmodes & WWM_UL) + wwaddcap1(WWT_UL, &kp); + if (wwavailmodes & WWM_GRP) + wwaddcap1(WWT_GRP, &kp); + if (wwavailmodes & WWM_DIM) + wwaddcap1(WWT_DIM, &kp); + if (wwavailmodes & WWM_USR) + wwaddcap1(WWT_USR, &kp); + if (tt.tt_insline && tt.tt_delline || tt.tt_setscroll) + wwaddcap1(WWT_ALDL, &kp); + if (tt.tt_inschar) + wwaddcap1(WWT_IMEI, &kp); + if (tt.tt_insspace) + wwaddcap1(WWT_IC, &kp); + if (tt.tt_delchar) + wwaddcap1(WWT_DC, &kp); + wwaddcap("kb", &kp); + wwaddcap("ku", &kp); + wwaddcap("kd", &kp); + wwaddcap("kl", &kp); + wwaddcap("kr", &kp); + wwaddcap("kh", &kp); + if ((j = tgetnum("kn")) >= 0) { + char cap[32]; + + (void) sprintf(kp, "kn#%d:", j); + for (; *kp; kp++) + ; + for (i = 1; i <= j; i++) { + (void) sprintf(cap, "k%d", i); + wwaddcap(cap, &kp); + cap[0] = 'l'; + wwaddcap(cap, &kp); + } + } + /* + * It's ok to do this here even if setenv() is destructive + * since tt_init() has already made its own copy of it and + * wwterm now points to the copy. + */ + (void) setenv("TERM", WWT_TERM, 1); +#ifdef TERMINFO + if (wwterminfoinit() < 0) + goto bad; +#endif + + if (tt.tt_checkpoint) + if (signal(SIGALRM, wwalarm) == BADSIG) { + wwerrno = WWE_SYS; + goto bad; + } + /* catch typeahead before ASYNC was set */ + (void) kill(getpid(), SIGIO); + wwstart1(); + (void) sigsetmask(s); + return 0; +bad: + /* + * Don't bother to free storage. We're supposed + * to exit when wwinit fails anyway. + */ + (void) wwsettty(0, &wwoldtty); + (void) signal(SIGIO, SIG_DFL); + (void) sigsetmask(s); + return -1; +} + +wwaddcap(cap, kp) + register char *cap; + register char **kp; +{ + char tbuf[512]; + char *tp = tbuf; + register char *str, *p; + + if ((str = tgetstr(cap, &tp)) != 0) { + while (*(*kp)++ = *cap++) + ; + (*kp)[-1] = '='; + while (*str) { + for (p = unctrl(*str++); *(*kp)++ = *p++;) + ; + (*kp)--; + } + *(*kp)++ = ':'; + **kp = 0; + } +} + +wwaddcap1(cap, kp) + register char *cap; + register char **kp; +{ + while (*(*kp)++ = *cap++) + ; + (*kp)--; +} + +wwstart() +{ + register i; + + (void) wwsettty(0, &wwnewtty); + for (i = 0; i < wwnrow; i++) + wwtouched[i] = WWU_TOUCHED; + wwstart1(); +} + +wwstart1() +{ + register i, j; + + for (i = 0; i < wwnrow; i++) + for (j = 0; j < wwncol; j++) { + wwos[i][j].c_w = ' '; + if (tt.tt_checkpoint) + wwcs[i][j].c_w = ' '; + } + xxstart(); + if (tt.tt_checkpoint) + wwdocheckpoint = 1; +} + +/* + * Reset data structures and terminal from an unknown state. + * Restoring wwos has been taken care of elsewhere. + */ +wwreset() +{ + register i; + + xxreset(); + for (i = 0; i < wwnrow; i++) + wwtouched[i] = WWU_TOUCHED; +} diff --git a/usr.bin/window/wwinschar.c b/usr.bin/window/wwinschar.c new file mode 100644 index 0000000..d055fcd --- /dev/null +++ b/usr.bin/window/wwinschar.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwinschar.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwinschar(w, row, col, c, m) +register struct ww *w; +char c, m; +{ + register i; + int nvis; + short x = c | m << WWC_MSHIFT; + + /* + * First, shift the line. + */ + { + register union ww_char *p, *q; + + p = &w->ww_buf[row][w->ww_b.r]; + q = p - 1; + for (i = w->ww_b.r - col; --i > 0;) + *--p = *--q; + q->c_w = x; + } + + /* + * If can't see it, just return. + */ + if (row < w->ww_i.t || row >= w->ww_i.b + || w->ww_i.r <= 0 || w->ww_i.r <= col) + return; + + if (col < w->ww_i.l) + col = w->ww_i.l; + + /* + * Now find out how much is actually changed, and fix wwns. + */ + { + register union ww_char *buf; + register char *win; + register union ww_char *ns; + register char *smap; + char touched; + + nvis = 0; + smap = &wwsmap[row][col]; + for (i = col; i < w->ww_i.r && *smap++ != w->ww_index; i++) + ; + if (i >= w->ww_i.r) + return; + col = i; + buf = w->ww_buf[row]; + win = w->ww_win[row]; + ns = wwns[row]; + smap = &wwsmap[row][i]; + touched = wwtouched[row]; + for (; i < w->ww_i.r; i++) { + if (*smap++ != w->ww_index) + continue; + touched |= WWU_TOUCHED; + if (win[i]) + ns[i].c_w = + buf[i].c_w ^ win[i] << WWC_MSHIFT; + else { + nvis++; + ns[i] = buf[i]; + } + } + wwtouched[row] = touched; + } + + /* + * Can/Should we use delete character? + */ + if ((tt.tt_inschar || tt.tt_insspace) && nvis > (wwncol - col) / 2) { + register union ww_char *p, *q; + + if (tt.tt_inschar) + xxinschar(row, col, c, m); + else { + xxinsspace(row, col); + x = ' '; + } + p = &wwos[row][wwncol]; + q = p - 1; + for (i = wwncol - col; --i > 0;) + *--p = *--q; + q->c_w = x; + } +} diff --git a/usr.bin/window/wwinsline.c b/usr.bin/window/wwinsline.c new file mode 100644 index 0000000..acdeb26 --- /dev/null +++ b/usr.bin/window/wwinsline.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwinsline.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwinsline(w, row) +register struct ww *w; +int row; +{ + register i; + register union ww_char **cpp, **cqq; + register union ww_char *cp; + int row1, row2; + char deleted; + int visible; + + /* + * Scroll first. + */ + if ((row1 = row) < w->ww_i.t) { + row1 = w->ww_i.t; + visible = 0; + } else + visible = 1; + if ((row2 = w->ww_b.b) > w->ww_i.b) { + row2 = w->ww_i.b; + } + deleted = wwscroll1(w, row1, row2, -1, visible); + + /* + * Fix the buffer. + * But leave clearing the last line for wwclreol(). + */ + cpp = &w->ww_buf[w->ww_b.b]; + cqq = cpp - 1; + cp = *cqq; + for (i = w->ww_b.b - row; --i > 0;) + *--cpp = *--cqq; + *cqq = cp; + + /* + * Now clear the last line. + */ + if (visible) + wwclreol1(w, row, w->ww_b.l, deleted); + else { + cp += w->ww_b.l; + for (i = w->ww_b.nc; --i >= 0;) + cp++->c_w = ' '; + } +} diff --git a/usr.bin/window/wwiomux.c b/usr.bin/window/wwiomux.c new file mode 100644 index 0000000..ce6978b --- /dev/null +++ b/usr.bin/window/wwiomux.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwiomux.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include +#include +#if !defined(OLD_TTY) && !defined(TIOCPKT_DATA) +#include +#endif +#include + +/* + * Multiple window output handler. + * The idea is to copy window outputs to the terminal, via the + * display package. We try to give wwcurwin highest priority. + * The only return conditions are when there is keyboard input + * and when a child process dies, which are serviced by signal + * catchers (wwrint() and wwchild()). + * When there's nothing to do, we sleep in a select(). + * This can be done better with interrupt driven io. But that's + * not supported on ptys, yet. + * The history of this routine is interesting. + */ +wwiomux() +{ + register struct ww *w; + fd_set imask; + register n; + register char *p; + char c; + struct timeval tv; + char noblock = 0; + + for (;;) { + if (wwinterrupt()) { + wwclrintr(); + return; + } + + FD_ZERO(&imask); + n = -1; + for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { + if (w->ww_pty < 0) + continue; + if (w->ww_obq < w->ww_obe) { + if (w->ww_pty > n) + n = w->ww_pty; + FD_SET(w->ww_pty, &imask); + } + if (w->ww_obq > w->ww_obp && !w->ww_stopped) + noblock = 1; + } + + if (!noblock) { + if (wwcurwin != 0) + wwcurtowin(wwcurwin); + wwupdate(); + wwflush(); + (void) setjmp(wwjmpbuf); + wwsetjmp = 1; + if (wwinterrupt()) { + wwsetjmp = 0; + wwclrintr(); + return; + } + /* + * Defensive code. If somebody else (for example, + * wall) clears the ASYNC flag on us, we will block + * forever. So we need a finite timeout and set + * the flag again. Anything more clever will probably + * need even more system calls. (This is a bug + * in the kernel.) + * I don't like this one bit. + */ + (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); + tv.tv_sec = 30; + tv.tv_usec = 0; + } else { + tv.tv_sec = 0; + tv.tv_usec = 10000; + } + wwnselect++; + n = select(n + 1, &imask, (fd_set *)0, (fd_set *)0, &tv); + wwsetjmp = 0; + noblock = 0; + + if (n < 0) + wwnselecte++; + else if (n == 0) + wwnselectz++; + else + for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { + if (w->ww_pty < 0 || + !FD_ISSET(w->ww_pty, &imask)) + continue; + wwnwread++; + p = w->ww_obq; + if (w->ww_ispty) { + if (p == w->ww_ob) { + w->ww_obp++; + w->ww_obq++; + } else + p--; + c = *p; + } + n = read(w->ww_pty, p, w->ww_obe - p); + if (n < 0) { + wwnwreade++; + (void) close(w->ww_pty); + w->ww_pty = -1; + } else if (n == 0) { + wwnwreadz++; + (void) close(w->ww_pty); + w->ww_pty = -1; + } else if (!w->ww_ispty) { + wwnwreadd++; + wwnwreadc += n; + w->ww_obq += n; + } else if (*p == TIOCPKT_DATA) { + n--; + wwnwreadd++; + wwnwreadc += n; + w->ww_obq += n; + } else { + wwnwreadp++; + if (*p & TIOCPKT_STOP) + w->ww_stopped = 1; + if (*p & TIOCPKT_START) + w->ww_stopped = 0; + if (*p & TIOCPKT_FLUSHWRITE) { + w->ww_stopped = 0; + w->ww_obq = w->ww_obp = + w->ww_ob; + } + } + if (w->ww_ispty) + *p = c; + } + /* + * Try the current window first, if there is output + * then process it and go back to the top to try again. + * This can lead to starvation of the other windows, + * but presumably that what we want. + * Update will eventually happen when output from wwcurwin + * dies down. + */ + if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && + w->ww_obq > w->ww_obp && !w->ww_stopped) { + n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); + if ((w->ww_obp += n) == w->ww_obq) + w->ww_obq = w->ww_obp = w->ww_ob; + noblock = 1; + continue; + } + for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) + if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && + !w->ww_stopped) { + n = wwwrite(w, w->ww_obp, + w->ww_obq - w->ww_obp); + if ((w->ww_obp += n) == w->ww_obq) + w->ww_obq = w->ww_obp = w->ww_ob; + if (wwinterrupt()) + break; + } + } +} diff --git a/usr.bin/window/wwlabel.c b/usr.bin/window/wwlabel.c new file mode 100644 index 0000000..d78e1f2 --- /dev/null +++ b/usr.bin/window/wwlabel.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwlabel.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "char.h" + +/* + * Label window w on f, + * at 1 line above w and 'where' columns from it's left edge. + * Gross, but it works. + */ +wwlabel(w, f, where, l, mode) +struct ww *w; +struct ww *f; +char *l; +{ + int row; + register j; + int jj; + register char *win; + register union ww_char *buf; + register union ww_char *ns; + register char *fmap; + register char *smap; + char touched; + char *p; + + if (f->ww_fmap == 0) + return; + + row = w->ww_w.t - 1; + if (row < f->ww_i.t || row >= f->ww_i.b) + return; + win = f->ww_win[row]; + buf = f->ww_buf[row]; + fmap = f->ww_fmap[row]; + ns = wwns[row]; + smap = wwsmap[row]; + touched = wwtouched[row]; + mode <<= WWC_MSHIFT; + + jj = MIN(w->ww_i.r, f->ww_i.r); + j = w->ww_i.l + where; + while (j < jj && *l) + for (p = unctrl(*l++); j < jj && *p; j++, p++) { + /* can't label if not already framed */ + if (win[j] & WWM_GLS) + continue; + if (smap[j] != f->ww_index) + buf[j].c_w = mode | *p; + else { + ns[j].c_w = (buf[j].c_w = mode | *p) + ^ win[j] << WWC_MSHIFT; + touched |= WWU_TOUCHED; + } + fmap[j] |= WWF_LABEL; + } + wwtouched[row] = touched; +} diff --git a/usr.bin/window/wwmisc.c b/usr.bin/window/wwmisc.c new file mode 100644 index 0000000..3fca477 --- /dev/null +++ b/usr.bin/window/wwmisc.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwmisc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include "char.h" + +/* + * Sufficient but not necessary test for total visibility. + */ +wwvisible(w) +register struct ww *w; +{ + register i; + register nvis = 0; + + for (i = w->ww_i.t; i < w->ww_i.b; i++) + nvis += w->ww_nvis[i]; + if (w->ww_hascursor + && w->ww_cur.r >= w->ww_i.t && w->ww_cur.r < w->ww_i.b + && w->ww_cur.c >= w->ww_i.l && w->ww_cur.c < w->ww_i.r + && wwsmap[w->ww_cur.r][w->ww_cur.c] == w->ww_index) + nvis++; + return nvis == w->ww_i.nr * w->ww_i.nc; +} + +wwbell() +{ + ttputc(ctrl('g')); +} diff --git a/usr.bin/window/wwmove.c b/usr.bin/window/wwmove.c new file mode 100644 index 0000000..65440d1 --- /dev/null +++ b/usr.bin/window/wwmove.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwmove.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +/* + * Move a window. Should be unattached. + */ +wwmove(w, row, col) +register struct ww *w; +{ + register dr, dc; + register i; + + dr = row - w->ww_w.t; + dc = col - w->ww_w.l; + + w->ww_w.t += dr; + w->ww_w.b += dr; + w->ww_w.l += dc; + w->ww_w.r += dc; + + w->ww_b.t += dr; + w->ww_b.b += dr; + w->ww_b.l += dc; + w->ww_b.r += dc; + + w->ww_i.t = MAX(w->ww_w.t, 0); + w->ww_i.b = MIN(w->ww_w.b, wwnrow); + w->ww_i.nr = w->ww_i.b - w->ww_i.t; + w->ww_i.l = MAX(w->ww_w.l, 0); + w->ww_i.r = MIN(w->ww_w.r, wwncol); + w->ww_i.nc = w->ww_i.r - w->ww_i.l; + + w->ww_cur.r += dr; + w->ww_cur.c += dc; + + w->ww_win -= dr; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + w->ww_win[i] -= dc; + if (w->ww_fmap != 0) { + w->ww_fmap -= dr; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + w->ww_fmap[i] -= dc; + } + w->ww_nvis -= dr; + for (i = w->ww_i.t; i < w->ww_i.b; i++) { + register j = w->ww_i.l; + register char *win = &w->ww_win[i][j]; + register char *smap = &wwsmap[i][j]; + int nvis = 0; + + for (; j < w->ww_i.r; j++, win++, smap++) + if (*win == 0 && *smap == w->ww_index) + nvis++; + w->ww_nvis[i] = nvis; + } + w->ww_buf -= dr; + for (i = w->ww_b.t; i < w->ww_b.b; i++) + w->ww_buf[i] -= dc; +} diff --git a/usr.bin/window/wwopen.c b/usr.bin/window/wwopen.c new file mode 100644 index 0000000..c4fc96b --- /dev/null +++ b/usr.bin/window/wwopen.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwopen.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include +#include +#include + +struct ww * +wwopen(flags, nrow, ncol, row, col, nline) +{ + register struct ww *w; + register i, j; + char m; + short nvis; + + w = (struct ww *)calloc(sizeof (struct ww), 1); + if (w == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + w->ww_pty = -1; + w->ww_socket = -1; + + for (i = 0; i < NWW && wwindex[i] != 0; i++) + ; + if (i >= NWW) { + wwerrno = WWE_TOOMANY; + goto bad; + } + w->ww_index = i; + + if (nline < nrow) + nline = nrow; + + w->ww_w.t = row; + w->ww_w.b = row + nrow; + w->ww_w.l = col; + w->ww_w.r = col + ncol; + w->ww_w.nr = nrow; + w->ww_w.nc = ncol; + + w->ww_b.t = row; + w->ww_b.b = row + nline; + w->ww_b.l = col; + w->ww_b.r = col + ncol; + w->ww_b.nr = nline; + w->ww_b.nc = ncol; + + w->ww_i.t = MAX(w->ww_w.t, 0); + w->ww_i.b = MIN(w->ww_w.b, wwnrow); + w->ww_i.l = MAX(w->ww_w.l, 0); + w->ww_i.r = MIN(w->ww_w.r, wwncol); + w->ww_i.nr = w->ww_i.b - w->ww_i.t; + w->ww_i.nc = w->ww_i.r - w->ww_i.l; + + w->ww_cur.r = w->ww_w.t; + w->ww_cur.c = w->ww_w.l; + + if (flags & WWO_PTY) { + if (wwgetpty(w) < 0) + goto bad; + w->ww_ispty = 1; + } else if (flags & WWO_SOCKET) { + int d[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, d) < 0) { + wwerrno = WWE_SYS; + goto bad; + } + (void) fcntl(d[0], F_SETFD, 1); + (void) fcntl(d[1], F_SETFD, 1); + w->ww_pty = d[0]; + w->ww_socket = d[1]; + } + if (flags & (WWO_PTY|WWO_SOCKET)) { + if ((w->ww_ob = malloc(512)) == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + w->ww_obe = w->ww_ob + 512; + w->ww_obp = w->ww_obq = w->ww_ob; + } + + w->ww_win = wwalloc(w->ww_w.t, w->ww_w.l, + w->ww_w.nr, w->ww_w.nc, sizeof (char)); + if (w->ww_win == 0) + goto bad; + m = 0; + if (flags & WWO_GLASS) + m |= WWM_GLS; + if (flags & WWO_REVERSE) + if (wwavailmodes & WWM_REV) + m |= WWM_REV; + else + flags &= ~WWO_REVERSE; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + for (j = w->ww_w.l; j < w->ww_w.r; j++) + w->ww_win[i][j] = m; + + if (flags & WWO_FRAME) { + w->ww_fmap = wwalloc(w->ww_w.t, w->ww_w.l, + w->ww_w.nr, w->ww_w.nc, sizeof (char)); + if (w->ww_fmap == 0) + goto bad; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + for (j = w->ww_w.l; j < w->ww_w.r; j++) + w->ww_fmap[i][j] = 0; + } + + w->ww_buf = (union ww_char **) + wwalloc(w->ww_b.t, w->ww_b.l, + w->ww_b.nr, w->ww_b.nc, sizeof (union ww_char)); + if (w->ww_buf == 0) + goto bad; + for (i = w->ww_b.t; i < w->ww_b.b; i++) + for (j = w->ww_b.l; j < w->ww_b.r; j++) + w->ww_buf[i][j].c_w = ' '; + + w->ww_nvis = (short *)malloc((unsigned) w->ww_w.nr * sizeof (short)); + if (w->ww_nvis == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + w->ww_nvis -= w->ww_w.t; + nvis = m ? 0 : w->ww_w.nc; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + w->ww_nvis[i] = nvis; + + w->ww_state = WWS_INITIAL; + w->ww_oflags = flags; + return wwindex[w->ww_index] = w; +bad: + if (w != 0) { + if (w->ww_win != 0) + wwfree(w->ww_win, w->ww_w.t); + if (w->ww_fmap != 0) + wwfree(w->ww_fmap, w->ww_w.t); + if (w->ww_buf != 0) + wwfree((char **)w->ww_buf, w->ww_b.t); + if (w->ww_nvis != 0) + free((char *)(w->ww_nvis + w->ww_w.t)); + if (w->ww_ob != 0) + free(w->ww_ob); + if (w->ww_pty >= 0) + (void) close(w->ww_pty); + if (w->ww_socket >= 0) + (void) close(w->ww_socket); + free((char *)w); + } + return 0; +} diff --git a/usr.bin/window/wwprintf.c b/usr.bin/window/wwprintf.c new file mode 100644 index 0000000..8df9d13 --- /dev/null +++ b/usr.bin/window/wwprintf.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwprintf.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include + +/*VARARGS2*/ +wwprintf(w, fmt, va_alist) +struct ww *w; +char *fmt; +va_dcl +{ + char buf[1024]; + va_list ap; + + va_start(ap); + /* buffer can overflow */ + (void) wwwrite(w, buf, vsprintf(buf, fmt, ap)); + va_end(ap); +} diff --git a/usr.bin/window/wwpty.c b/usr.bin/window/wwpty.c new file mode 100644 index 0000000..1d82ff9 --- /dev/null +++ b/usr.bin/window/wwpty.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwpty.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include +#if !defined(OLD_TTY) && !defined(TIOCPKT) +#include +#endif + +wwgetpty(w) +register struct ww *w; +{ + register char c, *p; + int tty; + int on = 1; +#define PTY "/dev/XtyXX" +#define _PT 5 +#define _PQRS 8 +#define _0_9 9 + + (void) strcpy(w->ww_ttyname, PTY); + for (c = 'p'; c <= 'u'; c++) { + w->ww_ttyname[_PT] = 'p'; + w->ww_ttyname[_PQRS] = c; + w->ww_ttyname[_0_9] = '0'; + if (access(w->ww_ttyname, 0) < 0) + break; + for (p = "0123456789abcdef"; *p; p++) { + w->ww_ttyname[_PT] = 'p'; + w->ww_ttyname[_0_9] = *p; + if ((w->ww_pty = open(w->ww_ttyname, 2)) < 0) + continue; + w->ww_ttyname[_PT] = 't'; + if ((tty = open(w->ww_ttyname, 2)) < 0) { + (void) close(w->ww_pty); + continue; + } + (void) close(tty); + if (ioctl(w->ww_pty, TIOCPKT, (char *)&on) < 0) { + (void) close(w->ww_pty); + continue; + } + (void) fcntl(w->ww_pty, F_SETFD, 1); + return 0; + } + } + w->ww_pty = -1; + wwerrno = WWE_NOPTY; + return -1; +} diff --git a/usr.bin/window/wwputc.c b/usr.bin/window/wwputc.c new file mode 100644 index 0000000..af614b2 --- /dev/null +++ b/usr.bin/window/wwputc.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwputc.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwputc(c, w) +char c; +struct ww *w; +{ + (void) wwwrite(w, &c, sizeof c); +} diff --git a/usr.bin/window/wwputs.c b/usr.bin/window/wwputs.c new file mode 100644 index 0000000..2584da2 --- /dev/null +++ b/usr.bin/window/wwputs.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwputs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwputs(s, w) +register char *s; +struct ww *w; +{ + register char *p = s; + + while (*p++) + ; + (void) wwwrite(w, s, p - s - 1); +} diff --git a/usr.bin/window/wwredraw.c b/usr.bin/window/wwredraw.c new file mode 100644 index 0000000..2a98012 --- /dev/null +++ b/usr.bin/window/wwredraw.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwredraw.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwredraw() +{ + register i, j; + register union ww_char *os; + + xxclear(); + for (i = 0; i < wwnrow; i++) { + wwtouched[i] = WWU_TOUCHED; + os = wwos[i]; + for (j = wwncol; --j >= 0;) + (os++)->c_w = ' '; + } +} diff --git a/usr.bin/window/wwredrawwin.c b/usr.bin/window/wwredrawwin.c new file mode 100644 index 0000000..36590df --- /dev/null +++ b/usr.bin/window/wwredrawwin.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwredrawwin.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwredrawwin1(w, row1, row2, offset) +register struct ww *w; +int row1, row2, offset; +{ + int row; + register col; + register char *smap; + register union ww_char *buf; + register char *win; + register union ww_char *ns; + int x; + int nchanged; + + for (row = row1; row < row2; row++) { + col = w->ww_i.l; + ns = wwns[row]; + smap = &wwsmap[row][col]; + buf = w->ww_buf[row + offset]; + win = w->ww_win[row]; + nchanged = 0; + for (; col < w->ww_i.r; col++) + if (*smap++ == w->ww_index && + ns[col].c_w != + (x = buf[col].c_w ^ win[col] << WWC_MSHIFT)) { + nchanged++; + ns[col].c_w = x; + } + if (nchanged > 0) + wwtouched[row] |= WWU_TOUCHED; + } +} diff --git a/usr.bin/window/wwrint.c b/usr.bin/window/wwrint.c new file mode 100644 index 0000000..0cd0901 --- /dev/null +++ b/usr.bin/window/wwrint.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwrint.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#if defined(OLD_TTY) || defined(VMIN_BUG) +#include +#endif + +/* + * Tty input interrupt handler. + * (1) Read input into buffer (wwib*). + * (2) Set the interrupt flag if anything is read. + * Currently, the last is used to get out of the blocking + * select() in wwiomux(). + * To avoid race conditions, we only modify wwibq in here, except + * when the buffer is empty; and everywhere else, we only change wwibp. + * It should be completely safe. + */ +void +wwrint() +{ + register n; + + if (wwibp == wwibq) + wwibp = wwibq = wwib; + wwnread++; +#if defined(OLD_TTY) || defined(VMIN_BUG) + /* we have set c_cc[VMIN] to 0 */ + (void) fcntl(0, F_SETFL, O_NONBLOCK|wwnewtty.ww_fflags); +#endif + n = read(0, wwibq, wwibe - wwibq); +#if defined(OLD_TTY) || defined(VMIN_BUG) + (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); +#endif + if (n > 0) { + if (tt.tt_rint) + n = (*tt.tt_rint)(wwibq, n); + if (n > 0) { + wwibq += n; + wwnreadc += n; + /* + * Hasten or delay the next checkpoint, + * as the case may be. + */ + if (tt.tt_checkpoint && !wwdocheckpoint) + (void) alarm(1); + wwsetintr(); + } + } else if (n == 0) + wwnreadz++; + else + wwnreade++; +} diff --git a/usr.bin/window/wwscroll.c b/usr.bin/window/wwscroll.c new file mode 100644 index 0000000..806e398 --- /dev/null +++ b/usr.bin/window/wwscroll.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwscroll.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwscroll(w, n) +register struct ww *w; +int n; +{ + register dir; + register top; + + if (n == 0) + return; + dir = n < 0 ? -1 : 1; + top = w->ww_b.t - n; + if (top > w->ww_w.t) + top = w->ww_w.t; + else if (top + w->ww_b.nr < w->ww_w.b) + top = w->ww_w.b - w->ww_b.nr; + n = abs(top - w->ww_b.t); + if (n < w->ww_i.nr) { + while (--n >= 0) { + (void) wwscroll1(w, w->ww_i.t, w->ww_i.b, dir, 0); + w->ww_buf += dir; + w->ww_b.t -= dir; + w->ww_b.b -= dir; + } + } else { + w->ww_buf -= top - w->ww_b.t; + w->ww_b.t = top; + w->ww_b.b = top + w->ww_b.nr; + wwredrawwin(w); + } +} + +/* + * Scroll one line, between 'row1' and 'row2', in direction 'dir'. + * Don't adjust ww_scroll. + * And don't redraw 'leaveit' lines. + */ +wwscroll1(w, row1, row2, dir, leaveit) +register struct ww *w; +int row1, row2, dir; +int leaveit; +{ + register i; + int row1x, row2x; + int nvis; + int nvismax; + int scrolled = 0; + + /* + * See how many lines on the screen are affected. + * And calculate row1x, row2x, and left at the same time. + */ + for (i = row1; i < row2 && w->ww_nvis[i] == 0; i++) + ; + if (i >= row2) /* can't do any fancy stuff */ + goto out; + row1x = i; + for (i = row2 - 1; i >= row1 && w->ww_nvis[i] == 0; i--) + ; + if (i <= row1x) + goto out; /* just one line is easy */ + row2x = i + 1; + + /* + * See how much of this window is visible. + */ + nvismax = wwncol * (row2x - row1x); + nvis = 0; + for (i = row1x; i < row2x; i++) + nvis += w->ww_nvis[i]; + + /* + * If it's a good idea to scroll and the terminal can, then do it. + */ + if (nvis < nvismax / 2) + goto no_scroll; /* not worth it */ + if ((dir > 0 ? tt.tt_scroll_down == 0 : tt.tt_scroll_up == 0) || + (tt.tt_scroll_top != row1x || tt.tt_scroll_bot != row2x - 1) && + tt.tt_setscroll == 0) + if (tt.tt_delline == 0 || tt.tt_insline == 0) + goto no_scroll; + xxscroll(dir, row1x, row2x); + scrolled = 1; + /* + * Fix up the old screen. + */ + { + register union ww_char *tmp; + register union ww_char **cpp, **cqq; + + if (dir > 0) { + cpp = &wwos[row1x]; + cqq = cpp + 1; + tmp = *cpp; + for (i = row2x - row1x; --i > 0;) + *cpp++ = *cqq++; + *cpp = tmp; + } else { + cpp = &wwos[row2x]; + cqq = cpp - 1; + tmp = *cqq; + for (i = row2x - row1x; --i > 0;) + *--cpp = *--cqq; + *cqq = tmp; + } + for (i = wwncol; --i >= 0;) + tmp++->c_w = ' '; + } + +no_scroll: + /* + * Fix the new screen. + */ + if (nvis == nvismax) { + /* + * Can shift whole lines. + */ + if (dir > 0) { + { + register union ww_char *tmp; + register union ww_char **cpp, **cqq; + + cpp = &wwns[row1x]; + cqq = cpp + 1; + tmp = *cpp; + for (i = row2x - row1x; --i > 0;) + *cpp++ = *cqq++; + *cpp = tmp; + } + if (scrolled) { + register char *p, *q; + + p = &wwtouched[row1x]; + q = p + 1; + for (i = row2x - row1x; --i > 0;) + *p++ = *q++; + *p |= WWU_TOUCHED; + } else { + register char *p; + + p = &wwtouched[row1x]; + for (i = row2x - row1x; --i >= 0;) + *p++ |= WWU_TOUCHED; + } + wwredrawwin1(w, row1, row1x, dir); + wwredrawwin1(w, row2x - 1, row2 - leaveit, dir); + } else { + { + register union ww_char *tmp; + register union ww_char **cpp, **cqq; + + cpp = &wwns[row2x]; + cqq = cpp - 1; + tmp = *cqq; + for (i = row2x - row1x; --i > 0;) + *--cpp = *--cqq; + *cqq = tmp; + } + if (scrolled) { + register char *p, *q; + + p = &wwtouched[row2x]; + q = p - 1; + for (i = row2x - row1x; --i > 0;) + *--p = *--q; + *q |= WWU_TOUCHED; + } else { + register char *p; + + p = &wwtouched[row1x]; + for (i = row2x - row1x; --i >= 0;) + *p++ |= WWU_TOUCHED; + } + wwredrawwin1(w, row1 + leaveit, row1x + 1, dir); + wwredrawwin1(w, row2x, row2, dir); + } + } else { + if (scrolled) { + register char *p; + + p = &wwtouched[row1x]; + for (i = row2x - row1x; --i >= 0;) + *p++ |= WWU_TOUCHED; + } +out: + if (dir > 0) + wwredrawwin1(w, row1, row2 - leaveit, dir); + else + wwredrawwin1(w, row1 + leaveit, row2, dir); + } + return scrolled; +} diff --git a/usr.bin/window/wwsize.c b/usr.bin/window/wwsize.c new file mode 100644 index 0000000..7dee857 --- /dev/null +++ b/usr.bin/window/wwsize.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwsize.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +/* + * Resize a window. Should be unattached. + */ +wwsize(w, nrow, ncol) +register struct ww *w; +{ + register i, j; + int nline; + union ww_char **buf = 0; + char **win = 0; + short *nvis = 0; + char **fmap = 0; + char m; + + /* + * First allocate new buffers. + */ + win = wwalloc(w->ww_w.t, w->ww_w.l, nrow, ncol, sizeof (char)); + if (win == 0) + goto bad; + if (w->ww_fmap != 0) { + fmap = wwalloc(w->ww_w.t, w->ww_w.l, nrow, ncol, sizeof (char)); + if (fmap == 0) + goto bad; + } + if (nrow > w->ww_b.nr || ncol > w->ww_b.nc) { + nline = MAX(w->ww_b.nr, nrow); + buf = (union ww_char **) wwalloc(w->ww_b.t, w->ww_b.l, + nline, ncol, sizeof (union ww_char)); + if (buf == 0) + goto bad; + } + nvis = (short *)malloc((unsigned) nrow * sizeof (short)); + if (nvis == 0) { + wwerrno = WWE_NOMEM; + goto bad; + } + nvis -= w->ww_w.t; + /* + * Copy text buffer. + */ + if (buf != 0) { + int b, r; + + b = w->ww_b.t + nline; + r = w->ww_b.l + ncol; + if (ncol < w->ww_b.nc) + for (i = w->ww_b.t; i < w->ww_b.b; i++) + for (j = w->ww_b.l; j < r; j++) + buf[i][j] = w->ww_buf[i][j]; + else + for (i = w->ww_b.t; i < w->ww_b.b; i++) { + for (j = w->ww_b.l; j < w->ww_b.r; j++) + buf[i][j] = w->ww_buf[i][j]; + for (; j < r; j++) + buf[i][j].c_w = ' '; + } + for (; i < b; i++) + for (j = w->ww_b.l; j < r; j++) + buf[i][j].c_w = ' '; + } + /* + * Now free the old stuff. + */ + wwfree((char **)w->ww_win, w->ww_w.t); + w->ww_win = win; + if (buf != 0) { + wwfree((char **)w->ww_buf, w->ww_b.t); + w->ww_buf = buf; + } + if (w->ww_fmap != 0) { + wwfree((char **)w->ww_fmap, w->ww_w.t); + w->ww_fmap = fmap; + } + free((char *)(w->ww_nvis + w->ww_w.t)); + w->ww_nvis = nvis; + /* + * Set new sizes. + */ + /* window */ + w->ww_w.b = w->ww_w.t + nrow; + w->ww_w.r = w->ww_w.l + ncol; + w->ww_w.nr = nrow; + w->ww_w.nc = ncol; + /* text buffer */ + if (buf != 0) { + w->ww_b.b = w->ww_b.t + nline; + w->ww_b.r = w->ww_b.l + ncol; + w->ww_b.nr = nline; + w->ww_b.nc = ncol; + } + /* scroll */ + if ((i = w->ww_b.b - w->ww_w.b) < 0 || + (i = w->ww_cur.r - w->ww_w.b + 1) > 0) { + w->ww_buf += i; + w->ww_b.t -= i; + w->ww_b.b -= i; + w->ww_cur.r -= i; + } + /* interior */ + w->ww_i.b = MIN(w->ww_w.b, wwnrow); + w->ww_i.r = MIN(w->ww_w.r, wwncol); + w->ww_i.nr = w->ww_i.b - w->ww_i.t; + w->ww_i.nc = w->ww_i.r - w->ww_i.l; + /* + * Initialize new buffers. + */ + /* window */ + m = 0; + if (w->ww_oflags & WWO_GLASS) + m |= WWM_GLS; + if (w->ww_oflags & WWO_REVERSE) + m |= WWM_REV; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + for (j = w->ww_w.l; j < w->ww_w.r; j++) + w->ww_win[i][j] = m; + /* frame map */ + if (fmap != 0) + for (i = w->ww_w.t; i < w->ww_w.b; i++) + for (j = w->ww_w.l; j < w->ww_w.r; j++) + w->ww_fmap[i][j] = 0; + /* visibility */ + j = m ? 0 : w->ww_w.nc; + for (i = w->ww_w.t; i < w->ww_w.b; i++) + w->ww_nvis[i] = j; + /* + * Put cursor back. + */ + if (w->ww_hascursor) { + w->ww_hascursor = 0; + wwcursor(w, 1); + } + /* + * Fool with pty. + */ + if (w->ww_ispty && w->ww_pty >= 0) + (void) wwsetttysize(w->ww_pty, nrow, ncol); + return 0; +bad: + if (win != 0) + wwfree(win, w->ww_w.t); + if (fmap != 0) + wwfree(fmap, w->ww_w.t); + if (buf != 0) + wwfree((char **)buf, w->ww_b.t); + if (nvis != 0) + free((char *)(nvis + w->ww_w.t)); + return -1; +} diff --git a/usr.bin/window/wwspawn.c b/usr.bin/window/wwspawn.c new file mode 100644 index 0000000..7c3c12b --- /dev/null +++ b/usr.bin/window/wwspawn.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwspawn.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include + +/* + * There is a dead lock with vfork and closing of pseudo-ports. + * So we have to be sneaky about error reporting. + */ +wwspawn(wp, file, argv) +register struct ww *wp; +char *file; +char **argv; +{ + int pid; + int ret; + char erred = 0; + int s; + + s = sigblock(sigmask(SIGCHLD)); + switch (pid = vfork()) { + case -1: + wwerrno = WWE_SYS; + ret = -1; + break; + case 0: + if (wwenviron(wp) >= 0) + execvp(file, argv); + erred = 1; + _exit(1); + default: + if (erred) { + wwerrno = WWE_SYS; + ret = -1; + } else { + wp->ww_pid = pid; + wp->ww_state = WWS_HASPROC; + ret = pid; + } + } + (void) sigsetmask(s); + if (wp->ww_socket >= 0) { + (void) close(wp->ww_socket); + wp->ww_socket = -1; + } + return ret; +} diff --git a/usr.bin/window/wwsuspend.c b/usr.bin/window/wwsuspend.c new file mode 100644 index 0000000..a67a130 --- /dev/null +++ b/usr.bin/window/wwsuspend.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwsuspend.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include + +wwsuspend() +{ + sig_t oldsig; + + oldsig = signal(SIGTSTP, SIG_IGN); + wwend(0); + (void) signal(SIGTSTP, SIG_DFL); + (void) kill(0, SIGTSTP); + (void) signal(SIGTSTP, SIG_IGN); + wwstart(); + (void) signal(SIGTSTP, oldsig); +} diff --git a/usr.bin/window/wwterminfo.c b/usr.bin/window/wwterminfo.c new file mode 100644 index 0000000..8039b1e --- /dev/null +++ b/usr.bin/window/wwterminfo.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1982, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwterminfo.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#ifdef TERMINFO + +#include "ww.h" +#include +#include +#include "local.h" + +/* + * Terminfo support + * + * Written by Brian Buhrow + * + * Subsequently modified by Edward Wang + */ + +/* + * Initialize the working terminfo directory + */ +wwterminfoinit() +{ + FILE *fp; + char buf[2048]; + + /* make the directory */ + (void) sprintf(wwterminfopath, "%swwinXXXXXX", _PATH_TMP); + mktemp(wwterminfopath); + if (mkdir(wwterminfopath, 0755) < 0 || + chmod(wwterminfopath, 00755) < 0) { + wwerrno = WWE_SYS; + return -1; + } + (void) setenv("TERMINFO", wwterminfopath, 1); + /* make a termcap entry and turn it into terminfo */ + (void) sprintf(buf, "%s/cap", wwterminfopath); + if ((fp = fopen(buf, "w")) == NULL) { + wwerrno = WWE_SYS; + return -1; + } + (void) fprintf(fp, "%sco#%d:li#%d:%s\n", + WWT_TERMCAP, wwncol, wwnrow, wwwintermcap); + (void) fclose(fp); + (void) sprintf(buf, + "cd %s; %s cap >info 2>/dev/null; %s info >/dev/null 2>&1", + wwterminfopath, _PATH_CAPTOINFO, _PATH_TIC); + (void) system(buf); + return 0; +} + +/* + * Delete the working terminfo directory at shutdown + */ +wwterminfoend() +{ + + switch (vfork()) { + case -1: + /* can't really do (or say) anything about errors */ + return -1; + case 0: + execl(_PATH_RM, _PATH_RM, "-rf", wwterminfopath, 0); + return -1; + default: + return 0; + } +} + +#endif /* TERMINFO */ diff --git a/usr.bin/window/wwtty.c b/usr.bin/window/wwtty.c new file mode 100644 index 0000000..2440389 --- /dev/null +++ b/usr.bin/window/wwtty.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwtty.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include +#include +#if !defined(OLD_TTY) && !defined(TIOCGWINSZ) +#include +#endif + +wwgettty(d, t) +register struct ww_tty *t; +{ +#ifdef OLD_TTY + if (ioctl(d, TIOCGETP, (char *)&t->ww_sgttyb) < 0) + goto bad; + if (ioctl(d, TIOCGETC, (char *)&t->ww_tchars) < 0) + goto bad; + if (ioctl(d, TIOCGLTC, (char *)&t->ww_ltchars) < 0) + goto bad; + if (ioctl(d, TIOCLGET, (char *)&t->ww_lmode) < 0) + goto bad; + if (ioctl(d, TIOCGETD, (char *)&t->ww_ldisc) < 0) + goto bad; +#else + if (tcgetattr(d, &t->ww_termios) < 0) + goto bad; +#endif + if ((t->ww_fflags = fcntl(d, F_GETFL, 0)) < 0) + goto bad; + return 0; +bad: + wwerrno = WWE_SYS; + return -1; +} + +/* + * Set the modes of tty 'd' to 't' + * 'o' is the current modes. We set the line discipline only if + * it changes, to avoid unnecessary flushing of typeahead. + */ +wwsettty(d, t) +register struct ww_tty *t; +{ +#ifdef OLD_TTY + int i; + + /* XXX, for buggy tty drivers that don't wait for output to drain */ + while (ioctl(d, TIOCOUTQ, &i) >= 0 && i > 0) + usleep(100000); + if (ioctl(d, TIOCSETN, (char *)&t->ww_sgttyb) < 0) + goto bad; + if (ioctl(d, TIOCSETC, (char *)&t->ww_tchars) < 0) + goto bad; + if (ioctl(d, TIOCSLTC, (char *)&t->ww_ltchars) < 0) + goto bad; + if (ioctl(d, TIOCLSET, (char *)&t->ww_lmode) < 0) + goto bad; + if (ioctl(d, TIOCGETD, (char *)&i) < 0) + goto bad; + if (t->ww_ldisc != i && + ioctl(d, TIOCSETD, (char *)&t->ww_ldisc) < 0) + goto bad; +#else +#ifdef sun + /* XXX, for buggy tty drivers that don't wait for output to drain */ + (void) tcdrain(d); +#endif + if (tcsetattr(d, TCSADRAIN, &t->ww_termios) < 0) + goto bad; +#endif + if (fcntl(d, F_SETFL, t->ww_fflags) < 0) + goto bad; + return 0; +bad: + wwerrno = WWE_SYS; + return -1; +} + +/* + * The ttysize and stop-start routines must also work + * on the control side of pseudoterminals. + */ + +wwgetttysize(d, r, c) + int *r, *c; +{ + struct winsize winsize; + + if (ioctl(d, TIOCGWINSZ, (char *)&winsize) < 0) { + wwerrno = WWE_SYS; + return -1; + } + if (winsize.ws_row != 0) + *r = winsize.ws_row; + if (winsize.ws_col != 0) + *c = winsize.ws_col; + return 0; +} + +wwsetttysize(d, r, c) +{ + struct winsize winsize; + + winsize.ws_row = r; + winsize.ws_col = c; + winsize.ws_xpixel = winsize.ws_ypixel = 0; + if (ioctl(d, TIOCSWINSZ, (char *)&winsize) < 0) { + wwerrno = WWE_SYS; + return -1; + } + return 0; +} + +wwstoptty(d) +{ +#if !defined(OLD_TTY) && defined(TCOOFF) + /* not guaranteed to work on the pty side */ + if (tcflow(d, TCOOFF) < 0) +#else + if (ioctl(d, TIOCSTOP, (char *)0) < 0) +#endif + { + wwerrno = WWE_SYS; + return -1; + } + return 0; +} + +wwstarttty(d) +{ +#if !defined(OLD_TTY) && defined(TCOON) + /* not guaranteed to work on the pty side */ + if (tcflow(d, TCOON) < 0) +#else + if (ioctl(d, TIOCSTART, (char *)0) < 0) +#endif + { + wwerrno = WWE_SYS; + return -1; + } + return 0; +} diff --git a/usr.bin/window/wwunframe.c b/usr.bin/window/wwunframe.c new file mode 100644 index 0000000..6945ffa --- /dev/null +++ b/usr.bin/window/wwunframe.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwunframe.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" + +wwunframe(w) +register struct ww *w; +{ + int i; + + for (i = w->ww_i.t; i < w->ww_i.b; i++) { + register j; + register char *win = w->ww_win[i]; + register char *fmap = w->ww_fmap ? w->ww_fmap[i] : 0; + register char *smap = wwsmap[i]; + register union ww_char *ns = wwns[i]; + int nchanged = 0; + + for (j = w->ww_i.l; j < w->ww_i.r; j++) { + if (win[j] & WWM_GLS) + continue; + win[j] |= WWM_GLS; + if (fmap != 0) + fmap[j] = 0; + if (smap[j] == w->ww_index) { + smap[j] = WWX_NOBODY; + ns[j].c_w = ' '; + nchanged++; + } + } + if (nchanged > 0) + wwtouched[i] |= WWU_TOUCHED; + w->ww_nvis[i] = 0; + } + + if (w->ww_forw != &wwhead) + wwdelete1(w->ww_forw, + w->ww_i.t, w->ww_i.b, w->ww_i.l, w->ww_i.r); +} diff --git a/usr.bin/window/wwupdate.c b/usr.bin/window/wwupdate.c new file mode 100644 index 0000000..f13453d --- /dev/null +++ b/usr.bin/window/wwupdate.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwupdate.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" + +wwupdate1(top, bot) +{ + int i; + register j; + char *touched; + struct ww_update *upd; + char check_clreos = 0; + int scan_top, scan_bot; + + wwnupdate++; + { + register char *t1 = wwtouched + top, *t2 = wwtouched + bot; + register n; + + while (!*t1++) + if (t1 == t2) + return; + while (!*--t2) + ; + scan_top = top = t1 - wwtouched - 1; + scan_bot = bot = t2 - wwtouched + 1; + if (scan_bot - scan_top > 1 && + (tt.tt_clreos != 0 || tt.tt_clear != 0)) { + int st = tt.tt_clreos != 0 ? scan_top : 0; + + /* + * t1 is one past the first touched row, + * t2 is on the last touched row. + */ + for (t1--, n = 1; t1 < t2;) + if (*t1++) + n++; + /* + * If we can't clreos then we try for clearing + * the whole screen. + */ + if (check_clreos = n * 10 > (wwnrow - st) * 9) { + scan_top = st; + scan_bot = wwnrow; + } + } + } + if (tt.tt_clreol == 0 && !check_clreos) + goto simple; + for (i = scan_top, touched = &wwtouched[i], upd = &wwupd[i]; + i < scan_bot; + i++, touched++, upd++) { + register gain = 0; + register best_gain = 0; + register best_col; + register union ww_char *ns, *os; + + if (wwinterrupt()) + return; + if (!check_clreos && !*touched) + continue; + wwnupdscan++; + j = wwncol; + ns = &wwns[i][j]; + os = &wwos[i][j]; + while (--j >= 0) { + /* + * The cost of clearing is: + * ncol - nblank + X + * The cost of straight update is, more or less: + * ncol - nsame + * We clear if nblank - nsame > X + * X is the clreol overhead. + * So we make gain = nblank - nsame. + */ + if ((--ns)->c_w == (--os)->c_w) + gain--; + else + best_gain--; + if (ns->c_w == ' ') + gain++; + if (gain > best_gain) { + best_col = j; + best_gain = gain; + } + } + upd->best_gain = best_gain; + upd->best_col = best_col; + upd->gain = gain; + } + if (check_clreos) { + register struct ww_update *u; + register gain = 0; + register best_gain = 0; + int best_row; + register simple_gain = 0; + char didit = 0; + + /* + * gain is the advantage of clearing all the lines. + * best_gain is the advantage of clearing to eos + * at best_row and u->best_col. + * simple_gain is the advantage of using only clreol. + * We use g > best_gain because u->best_col can be + * undefined when u->best_gain is 0 so we can't use it. + */ + for (j = scan_bot - 1, u = wwupd + j; j >= top; j--, u--) { + register g = gain + u->best_gain; + + if (g > best_gain) { + best_gain = g; + best_row = j; + } + gain += u->gain; + if (tt.tt_clreol != 0 && u->best_gain > 4) + simple_gain += u->best_gain - 4; + } + if (tt.tt_clreos == 0) { + if (gain > simple_gain && gain > 4) { + xxclear(); + i = top = scan_top; + bot = scan_bot; + j = 0; + didit = 1; + } + } else + if (best_gain > simple_gain && best_gain > 4) { + i = best_row; + xxclreos(i, j = wwupd[i].best_col); + bot = scan_bot; + didit = 1; + } + if (didit) { + wwnupdclreos++; + wwnupdclreosline += wwnrow - i; + u = wwupd + i; + while (i < scan_bot) { + register union ww_char *os = &wwos[i][j]; + + for (j = wwncol - j; --j >= 0;) + os++->c_w = ' '; + wwtouched[i++] |= WWU_TOUCHED; + u++->best_gain = 0; + j = 0; + } + } else + wwnupdclreosmiss++; + } +simple: + for (i = top, touched = &wwtouched[i], upd = &wwupd[i]; i < bot; + i++, touched++, upd++) { + register union ww_char *os, *ns; + char didit; + + if (!*touched) + continue; + *touched = 0; + wwnupdline++; + didit = 0; + if (tt.tt_clreol != 0 && upd->best_gain > 4) { + wwnupdclreol++; + xxclreol(i, j = upd->best_col); + for (os = &wwos[i][j], j = wwncol - j; --j >= 0;) + os++->c_w = ' '; + didit = 1; + } + ns = wwns[i]; + os = wwos[i]; + for (j = 0; j < wwncol;) { + register char *p, *q; + char m; + int c; + register n; + char buf[512]; /* > wwncol */ + union ww_char lastc; + + for (; j++ < wwncol && ns++->c_w == os++->c_w;) + ; + if (j > wwncol) + break; + p = buf; + m = ns[-1].c_m; + c = j - 1; + os[-1] = ns[-1]; + *p++ = ns[-1].c_c; + n = 5; + q = p; + while (j < wwncol && ns->c_m == m) { + *p++ = ns->c_c; + if (ns->c_w == os->c_w) { + if (--n <= 0) + break; + os++; + ns++; + } else { + n = 5; + q = p; + lastc = *os; + *os++ = *ns++; + } + j++; + } + n = q - buf; + if (!wwwrap || i != wwnrow - 1 || c + n != wwncol) + xxwrite(i, c, buf, n, m); + else if (tt.tt_inschar || tt.tt_insspace) { + if (n > 1) { + q[-2] = q[-1]; + n--; + } else + c--; + xxwrite(i, c, buf, n, m); + c += n - 1; + if (tt.tt_inschar) + xxinschar(i, c, ns[-2].c_c, + ns[-2].c_m); + else { + xxinsspace(i, c); + xxwrite(i, c, &ns[-2].c_c, 1, + ns[-2].c_m); + } + } else { + if (--n) + xxwrite(i, c, buf, n, m); + os[-1] = lastc; + *touched = WWU_TOUCHED; + } + didit = 1; + } + if (!didit) + wwnupdmiss++; + } +} diff --git a/usr.bin/window/wwwrite.c b/usr.bin/window/wwwrite.c new file mode 100644 index 0000000..d406cbc --- /dev/null +++ b/usr.bin/window/wwwrite.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)wwwrite.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "tt.h" +#include "char.h" + +#define UPDATE() \ + if (!w->ww_noupdate && w->ww_cur.r >= 0 && w->ww_cur.r < wwnrow && \ + wwtouched[w->ww_cur.r]) \ + wwupdate1(w->ww_cur.r, w->ww_cur.r + 1) + +/* + * To support control character expansion, we save the old + * p and q values in r and s, and point p at the beginning + * of the expanded string, and q at some safe place beyond it + * (p + 10). At strategic points in the loops, we check + * for (r && !*p) and restore the saved values back into + * p and q. Essentially, we implement a stack of depth 2, + * to avoid recursion, which might be a better idea. + */ +wwwrite(w, p, n) +register struct ww *w; +register char *p; +int n; +{ + char hascursor; + char *savep = p; + char *q = p + n; + char *r = 0; + char *s; + +#ifdef lint + s = 0; /* define it before possible use */ +#endif + if (hascursor = w->ww_hascursor) + wwcursor(w, 0); + while (p < q && !w->ww_stopped && (!wwinterrupt() || w->ww_nointr)) { + if (r && !*p) { + p = r; + q = s; + r = 0; + continue; + } + if (w->ww_wstate == 0 && + (isprt(*p) || w->ww_unctrl && isunctrl(*p))) { + register i; + register union ww_char *bp; + int col, col1; + + if (w->ww_insert) { /* this is very slow */ + if (*p == '\t') { + p++; + w->ww_cur.c += 8 - + (w->ww_cur.c - w->ww_w.l & 7); + goto chklf; + } + if (!isprt(*p)) { + r = p + 1; + s = q; + p = unctrl(*p); + q = p + 10; + } + wwinschar(w, w->ww_cur.r, w->ww_cur.c, + *p++, w->ww_modes); + goto right; + } + + bp = &w->ww_buf[w->ww_cur.r][w->ww_cur.c]; + i = w->ww_cur.c; + while (i < w->ww_w.r && p < q) + if (!*p && r) { + p = r; + q = s; + r = 0; + } else if (*p == '\t') { + register tmp = 8 - (i - w->ww_w.l & 7); + p++; + i += tmp; + bp += tmp; + } else if (isprt(*p)) { + bp++->c_w = *p++ + | w->ww_modes << WWC_MSHIFT; + i++; + } else if (w->ww_unctrl && isunctrl(*p)) { + r = p + 1; + s = q; + p = unctrl(*p); + q = p + 10; + } else + break; + col = MAX(w->ww_cur.c, w->ww_i.l); + col1 = MIN(i, w->ww_i.r); + w->ww_cur.c = i; + if (w->ww_cur.r >= w->ww_i.t + && w->ww_cur.r < w->ww_i.b) { + register union ww_char *ns = wwns[w->ww_cur.r]; + register char *smap = &wwsmap[w->ww_cur.r][col]; + register char *win = w->ww_win[w->ww_cur.r]; + int nchanged = 0; + + bp = w->ww_buf[w->ww_cur.r]; + for (i = col; i < col1; i++) + if (*smap++ == w->ww_index) { + nchanged++; + ns[i].c_w = bp[i].c_w + ^ win[i] << WWC_MSHIFT; + } + if (nchanged > 0) + wwtouched[w->ww_cur.r] |= WWU_TOUCHED; + } + chklf: + if (w->ww_cur.c >= w->ww_w.r) + goto crlf; + } else switch (w->ww_wstate) { + case 0: + switch (*p++) { + case '\n': + if (w->ww_mapnl) + crlf: + w->ww_cur.c = w->ww_w.l; + lf: + UPDATE(); + if (++w->ww_cur.r >= w->ww_w.b) { + w->ww_cur.r = w->ww_w.b - 1; + if (w->ww_w.b < w->ww_b.b) { + (void) wwscroll1(w, w->ww_i.t, + w->ww_i.b, 1, 0); + w->ww_buf++; + w->ww_b.t--; + w->ww_b.b--; + } else + wwdelline(w, w->ww_b.t); + } + break; + case '\b': + if (--w->ww_cur.c < w->ww_w.l) { + w->ww_cur.c = w->ww_w.r - 1; + goto up; + } + break; + case '\r': + w->ww_cur.c = w->ww_w.l; + break; + case ctrl('g'): + ttputc(ctrl('g')); + break; + case ctrl('['): + w->ww_wstate = 1; + break; + } + break; + case 1: + w->ww_wstate = 0; + switch (*p++) { + case '@': + w->ww_insert = 1; + break; + case 'A': + up: + UPDATE(); + if (--w->ww_cur.r < w->ww_w.t) { + w->ww_cur.r = w->ww_w.t; + if (w->ww_w.t > w->ww_b.t) { + (void) wwscroll1(w, w->ww_i.t, + w->ww_i.b, -1, 0); + w->ww_buf--; + w->ww_b.t++; + w->ww_b.b++; + } else + wwinsline(w, w->ww_b.t); + } + break; + case 'B': + goto lf; + case 'C': + right: + w->ww_cur.c++; + goto chklf; + case 'E': + w->ww_buf -= w->ww_w.t - w->ww_b.t; + w->ww_b.t = w->ww_w.t; + w->ww_b.b = w->ww_b.t + w->ww_b.nr; + w->ww_cur.r = w->ww_w.t; + w->ww_cur.c = w->ww_w.l; + wwclreos(w, w->ww_w.t, w->ww_w.l); + break; + case 'H': + UPDATE(); + w->ww_cur.r = w->ww_w.t; + w->ww_cur.c = w->ww_w.l; + break; + case 'J': + wwclreos(w, w->ww_cur.r, w->ww_cur.c); + break; + case 'K': + wwclreol(w, w->ww_cur.r, w->ww_cur.c); + break; + case 'L': + UPDATE(); + wwinsline(w, w->ww_cur.r); + break; + case 'M': + wwdelline(w, w->ww_cur.r); + break; + case 'N': + wwdelchar(w, w->ww_cur.r, w->ww_cur.c); + break; + case 'O': + w->ww_insert = 0; + break; + case 'P': + wwinschar(w, w->ww_cur.r, w->ww_cur.c, ' ', 0); + break; + case 'X': + wwupdate(); + break; + case 'Y': + UPDATE(); + w->ww_wstate = 2; + break; + case 'Z': + wwupdate(); + xxflush(0); + break; + case 's': + w->ww_wstate = 4; + break; + case 'r': + w->ww_wstate = 5; + break; + } + break; + case 2: + w->ww_cur.r = w->ww_w.t + + (unsigned)(*p++ - ' ') % w->ww_w.nr; + w->ww_wstate = 3; + break; + case 3: + w->ww_cur.c = w->ww_w.l + + (unsigned)(*p++ - ' ') % w->ww_w.nc; + w->ww_wstate = 0; + break; + case 4: + w->ww_modes |= *p++ & wwavailmodes; + w->ww_wstate = 0; + break; + case 5: + w->ww_modes &= ~*p++; + w->ww_wstate = 0; + break; + } + } + if (hascursor) + wwcursor(w, 1); + wwnwwr++; + wwnwwra += n; + n = p - savep; + wwnwwrc += n; + return n; +} diff --git a/usr.bin/window/xx.c b/usr.bin/window/xx.c new file mode 100644 index 0000000..9b68b96 --- /dev/null +++ b/usr.bin/window/xx.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)xx.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "xx.h" +#include "tt.h" + +xxinit() +{ + if (ttinit() < 0) + return -1; + xxbufsize = tt.tt_nrow * tt.tt_ncol * 2; + /* ccinit may choose to change xxbufsize */ + if (tt.tt_ntoken > 0 && ccinit() < 0) + return -1; + xxbuf = malloc((unsigned) xxbufsize * sizeof *xxbuf); + if (xxbuf == 0) { + wwerrno = WWE_NOMEM; + return -1; + } + xxbufp = xxbuf; + xxbufe = xxbuf + xxbufsize; + return 0; +} + +xxstart() +{ + (*tt.tt_start)(); + if (tt.tt_ntoken > 0) + ccstart(); + xxreset1(); /* might be a restart */ +} + +xxreset() +{ + if (tt.tt_ntoken > 0) + ccreset(); + xxreset1(); + (*tt.tt_reset)(); +} + +xxreset1() +{ + register struct xx *xp, *xq; + + for (xp = xx_head; xp != 0; xp = xq) { + xq = xp->link; + xxfree(xp); + } + xx_tail = xx_head = 0; + xxbufp = xxbuf; +} + +xxend() +{ + if (tt.tt_scroll_top != 0 || tt.tt_scroll_bot != tt.tt_nrow - 1) + /* tt.tt_setscroll is known to be defined */ + (*tt.tt_setscroll)(0, tt.tt_nrow - 1); + if (tt.tt_modes) + (*tt.tt_setmodes)(0); + if (tt.tt_scroll_down) + (*tt.tt_scroll_down)(1); + (*tt.tt_move)(tt.tt_nrow - 1, 0); + if (tt.tt_ntoken > 0) + ccend(); + (*tt.tt_end)(); + ttflush(); +} + +struct xx * +xxalloc() +{ + register struct xx *xp; + + if (xxbufp > xxbufe) + abort(); + if ((xp = xx_freelist) == 0) + /* XXX can't deal with failure */ + xp = (struct xx *) malloc((unsigned) sizeof *xp); + else + xx_freelist = xp->link; + if (xx_head == 0) + xx_head = xp; + else + xx_tail->link = xp; + xx_tail = xp; + xp->link = 0; + return xp; +} + +xxfree(xp) + register struct xx *xp; +{ + xp->link = xx_freelist; + xx_freelist = xp; +} + +xxmove(row, col) +{ + register struct xx *xp = xx_tail; + + if (xp == 0 || xp->cmd != xc_move) { + xp = xxalloc(); + xp->cmd = xc_move; + } + xp->arg0 = row; + xp->arg1 = col; +} + +xxscroll(dir, top, bot) +{ + register struct xx *xp = xx_tail; + + if (xp != 0 && xp->cmd == xc_scroll && + xp->arg1 == top && xp->arg2 == bot && + (xp->arg0 < 0 && dir < 0 || xp->arg0 > 0 && dir > 0)) { + xp->arg0 += dir; + return; + } + xp = xxalloc(); + xp->cmd = xc_scroll; + xp->arg0 = dir; + xp->arg1 = top; + xp->arg2 = bot; +} + +xxinschar(row, col, c, m) +{ + register struct xx *xp; + + xp = xxalloc(); + xp->cmd = xc_inschar; + xp->arg0 = row; + xp->arg1 = col; + xp->arg2 = c; + xp->arg3 = m; +} + +xxinsspace(row, col) +{ + register struct xx *xp = xx_tail; + + if (xp != 0 && xp->cmd == xc_insspace && xp->arg0 == row && + col >= xp->arg1 && col <= xp->arg1 + xp->arg2) { + xp->arg2++; + return; + } + xp = xxalloc(); + xp->cmd = xc_insspace; + xp->arg0 = row; + xp->arg1 = col; + xp->arg2 = 1; +} + +xxdelchar(row, col) +{ + register struct xx *xp = xx_tail; + + if (xp != 0 && xp->cmd == xc_delchar && + xp->arg0 == row && xp->arg1 == col) { + xp->arg2++; + return; + } + xp = xxalloc(); + xp->cmd = xc_delchar; + xp->arg0 = row; + xp->arg1 = col; + xp->arg2 = 1; +} + +xxclear() +{ + register struct xx *xp; + + xxreset1(); + xp = xxalloc(); + xp->cmd = xc_clear; +} + +xxclreos(row, col) +{ + register struct xx *xp = xxalloc(); + + xp->cmd = xc_clreos; + xp->arg0 = row; + xp->arg1 = col; +} + +xxclreol(row, col) +{ + register struct xx *xp = xxalloc(); + + xp->cmd = xc_clreol; + xp->arg0 = row; + xp->arg1 = col; +} + +xxwrite(row, col, p, n, m) + char *p; +{ + register struct xx *xp; + + if (xxbufp + n + 1 > xxbufe) + xxflush(0); + xp = xxalloc(); + xp->cmd = xc_write; + xp->arg0 = row; + xp->arg1 = col; + xp->arg2 = n; + xp->arg3 = m; + xp->buf = xxbufp; + bcopy(p, xxbufp, n); + xxbufp += n; + *xxbufp++ = char_sep; +} diff --git a/usr.bin/window/xx.h b/usr.bin/window/xx.h new file mode 100644 index 0000000..2c54589 --- /dev/null +++ b/usr.bin/window/xx.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)xx.h 8.1 (Berkeley) 6/6/93 + */ + +struct xx { + enum { xc_move, xc_scroll, xc_inschar, xc_insspace, xc_delchar, + xc_clear, xc_clreos, xc_clreol, xc_write } cmd; + int arg0; + int arg1; + int arg2; + int arg3; + char *buf; + struct xx *link; +}; + +struct xx *xxalloc(); + +struct xx *xx_head, *xx_tail; +struct xx *xx_freelist; + +char *xxbuf, *xxbufp, *xxbufe; +int xxbufsize; + +#define char_sep '\0' diff --git a/usr.bin/window/xxflush.c b/usr.bin/window/xxflush.c new file mode 100644 index 0000000..5b09579 --- /dev/null +++ b/usr.bin/window/xxflush.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Edward Wang at The University of California, Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)xxflush.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "ww.h" +#include "xx.h" +#include "tt.h" + +xxflush(intr) + register intr; +{ + register struct xx *xp, *xq; + + for (xp = xx_head; xp != 0 && !(intr && wwinterrupt()); xp = xq) { + switch (xp->cmd) { + case xc_move: + if (xp->link == 0) + (*tt.tt_move)(xp->arg0, xp->arg1); + break; + case xc_scroll: + xxflush_scroll(xp); + break; + case xc_inschar: + (*tt.tt_move)(xp->arg0, xp->arg1); + tt.tt_nmodes = xp->arg3; + (*tt.tt_inschar)(xp->arg2); + break; + case xc_insspace: + (*tt.tt_move)(xp->arg0, xp->arg1); + (*tt.tt_insspace)(xp->arg2); + break; + case xc_delchar: + (*tt.tt_move)(xp->arg0, xp->arg1); + (*tt.tt_delchar)(xp->arg2); + break; + case xc_clear: + (*tt.tt_clear)(); + break; + case xc_clreos: + (*tt.tt_move)(xp->arg0, xp->arg1); + (*tt.tt_clreos)(); + break; + case xc_clreol: + (*tt.tt_move)(xp->arg0, xp->arg1); + (*tt.tt_clreol)(); + break; + case xc_write: + (*tt.tt_move)(xp->arg0, xp->arg1); + tt.tt_nmodes = xp->arg3; + (*tt.tt_write)(xp->buf, xp->arg2); + break; + } + xq = xp->link; + xxfree(xp); + } + if ((xx_head = xp) == 0) { + xx_tail = 0; + xxbufp = xxbuf; + } + ttflush(); +} + +xxflush_scroll(xp) + register struct xx *xp; +{ + register struct xx *xq; + + top: + if (xp->arg0 == 0) + return; + /* + * We handle retain (da and db) by putting the burden on scrolling up, + * which is the less common operation. It must ensure that + * text is not pushed below the screen, so scrolling down doesn't + * have to worry about it. + * + * Try scrolling region (or scrolling the whole screen) first. + * Can we assume "sr" doesn't push text below the screen + * so we don't have to worry about retain below? + * What about scrolling down with a newline? It probably does + * push text above (with da). Scrolling up would then have + * to take care of that. + * It's easy to be fool proof, but that slows things down. + * The current solution is to disallow tt_scroll_up if da or db is true + * but cs (scrolling region) is not. Again, we sacrifice scrolling + * up in favor of scrolling down. The idea is having scrolling regions + * probably means we can scroll (even the whole screen) with impunity. + * This lets us work efficiently on simple terminals (use newline + * on the bottom to scroll), on any terminal without retain, and + * on vt100 style scrolling regions (I think). + */ + if (xp->arg0 > 0) { + if ((xq = xp->link) != 0 && xq->cmd == xc_scroll && + xp->arg2 == xq->arg2 && xq->arg0 < 0) { + if (xp->arg1 < xq->arg1) { + if (xp->arg2 - xp->arg0 <= xq->arg1) { + xq->arg0 = xp->arg0; + xq->arg1 = xp->arg1; + xq->arg2 = xp->arg2; + return; + } + xp->arg2 = xq->arg1 + xp->arg0; + xq->arg0 += xp->arg0; + xq->arg1 = xp->arg2; + if (xq->arg0 > 0) + xq->arg1 -= xq->arg0; + goto top; + } else { + if (xp->arg1 - xq->arg0 >= xp->arg2) + return; + xq->arg2 = xp->arg1 - xq->arg0; + xp->arg0 += xq->arg0; + xp->arg1 = xq->arg2; + if (xp->arg0 < 0) + xp->arg1 += xp->arg0; + goto top; + } + } + if (xp->arg0 > xp->arg2 - xp->arg1) + xp->arg0 = xp->arg2 - xp->arg1; + if (tt.tt_scroll_down) { + if (tt.tt_scroll_top != xp->arg1 || + tt.tt_scroll_bot != xp->arg2 - 1) { + if (tt.tt_setscroll == 0) + goto down; + (*tt.tt_setscroll)(xp->arg1, xp->arg2 - 1); + } + tt.tt_scroll_down(xp->arg0); + } else { + down: + (*tt.tt_move)(xp->arg1, 0); + (*tt.tt_delline)(xp->arg0); + if (xp->arg2 < tt.tt_nrow) { + (*tt.tt_move)(xp->arg2 - xp->arg0, 0); + (*tt.tt_insline)(xp->arg0); + } + } + } else { + xp->arg0 = - xp->arg0; + if (xp->arg0 > xp->arg2 - xp->arg1) + xp->arg0 = xp->arg2 - xp->arg1; + if (tt.tt_scroll_up) { + if (tt.tt_scroll_top != xp->arg1 || + tt.tt_scroll_bot != xp->arg2 - 1) { + if (tt.tt_setscroll == 0) + goto up; + (*tt.tt_setscroll)(xp->arg1, xp->arg2 - 1); + } + tt.tt_scroll_up(xp->arg0); + } else { + up: + if (tt.tt_retain || xp->arg2 != tt.tt_nrow) { + (*tt.tt_move)(xp->arg2 - xp->arg0, 0); + (*tt.tt_delline)(xp->arg0); + } + (*tt.tt_move)(xp->arg1, 0); + (*tt.tt_insline)(xp->arg0); + } + } +} diff --git a/usr.bin/write/Makefile b/usr.bin/write/Makefile new file mode 100644 index 0000000..8e6454b --- /dev/null +++ b/usr.bin/write/Makefile @@ -0,0 +1,7 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= write +BINMODE=2555 +BINGRP= tty + +.include diff --git a/usr.bin/write/write.1 b/usr.bin/write/write.1 new file mode 100644 index 0000000..89d7302 --- /dev/null +++ b/usr.bin/write/write.1 @@ -0,0 +1,108 @@ +.\" Copyright (c) 1989, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jef Poskanzer and Craig Leres of the 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. +.\" +.\" @(#)write.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt WRITE 1 +.Os +.Sh NAME +.Nm write +.Nd send a message to another user +.Sh SYNOPSIS +.Nm write +.Ar user +.Op Ar ttyname +.Sh DESCRIPTION +.Nm Write +allows you to communicate with other users, by copying lines from +your terminal to theirs. +.Pp +When you run the +.Nm write +command, the user you are writing to gets a message of the form: +.Pp +.Dl Message from yourname@yourhost on yourtty at hh:mm ... +.Pp +Any further lines you enter will be copied to the specified user's +terminal. +If the other user wants to reply, they must run +.Nm write +as well. +.Pp +When you are done, type an end-of-file or interrupt character. +The other user will see the message +.Ql EOF +indicating that the +conversation is over. +.Pp +You can prevent people (other than the super-user) from writing to you +with the +.Xr mesg 1 +command. +Some commands, for example +.Xr nroff 1 +and +.Xr pr 1 , +disallow writing automatically, so that your output isn't overwritten. +.Pp +If the user you want to write to is logged in on more than one terminal, +you can specify which terminal to write to by specifying the terminal +name as the second operand to the +.Nm write +command. +Alternatively, you can let +.Nm write +select one of the terminals \- it will pick the one with the shortest +idle time. +This is so that if the user is logged in at work and also dialed up from +home, the message will go to the right place. +.Pp +The traditional protocol for writing to someone is that the string +.Ql \-o , +either at the end of a line or on a line by itself, means that it's the +other person's turn to talk. +The string +.Ql oo +means that the person believes the conversation to be +over. +.Sh SEE ALSO +.Xr mesg 1 , +.Xr talk 1 , +.Xr who 1 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/usr.bin/write/write.c b/usr.bin/write/write.c new file mode 100644 index 0000000..7d99f21 --- /dev/null +++ b/usr.bin/write/write.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jef Poskanzer and Craig Leres of the 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int errno; + +main(argc, argv) + int argc; + char **argv; +{ + register char *cp; + time_t atime; + uid_t myuid; + int msgsok, myttyfd; + char tty[MAXPATHLEN], *mytty, *ttyname(); + void done(); + + /* check that sender has write enabled */ + if (isatty(fileno(stdin))) + myttyfd = fileno(stdin); + else if (isatty(fileno(stdout))) + myttyfd = fileno(stdout); + else if (isatty(fileno(stderr))) + myttyfd = fileno(stderr); + else { + (void)fprintf(stderr, "write: can't find your tty\n"); + exit(1); + } + if (!(mytty = ttyname(myttyfd))) { + (void)fprintf(stderr, "write: can't find your tty's name\n"); + exit(1); + } + if (cp = rindex(mytty, '/')) + mytty = cp + 1; + if (term_chk(mytty, &msgsok, &atime, 1)) + exit(1); + if (!msgsok) { + (void)fprintf(stderr, + "write: you have write permission turned off.\n"); + exit(1); + } + + myuid = getuid(); + + /* check args */ + switch (argc) { + case 2: + search_utmp(argv[1], tty, mytty, myuid); + do_write(tty, mytty, myuid); + break; + case 3: + if (!strncmp(argv[2], "/dev/", 5)) + argv[2] += 5; + if (utmp_chk(argv[1], argv[2])) { + (void)fprintf(stderr, + "write: %s is not logged in on %s.\n", + argv[1], argv[2]); + exit(1); + } + if (term_chk(argv[2], &msgsok, &atime, 1)) + exit(1); + if (myuid && !msgsok) { + (void)fprintf(stderr, + "write: %s has messages disabled on %s\n", + argv[1], argv[2]); + exit(1); + } + do_write(argv[2], mytty, myuid); + break; + default: + (void)fprintf(stderr, "usage: write user [tty]\n"); + exit(1); + } + done(); + /* NOTREACHED */ +} + +/* + * utmp_chk - checks that the given user is actually logged in on + * the given tty + */ +utmp_chk(user, tty) + char *user, *tty; +{ + struct utmp u; + int ufd; + + if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) + return(0); /* ignore error, shouldn't happen anyway */ + + while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u)) + if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 && + strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) { + (void)close(ufd); + return(0); + } + + (void)close(ufd); + return(1); +} + +/* + * search_utmp - search utmp for the "best" terminal to write to + * + * Ignores terminals with messages disabled, and of the rest, returns + * the one with the most recent access time. Returns as value the number + * of the user's terminals with messages enabled, or -1 if the user is + * not logged in at all. + * + * Special case for writing to yourself - ignore the terminal you're + * writing from, unless that's the only terminal with messages enabled. + */ +search_utmp(user, tty, mytty, myuid) + char *user, *tty, *mytty; + uid_t myuid; +{ + struct utmp u; + time_t bestatime, atime; + int ufd, nloggedttys, nttys, msgsok, user_is_me; + char atty[UT_LINESIZE + 1]; + + if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) { + perror("utmp"); + exit(1); + } + + nloggedttys = nttys = 0; + bestatime = 0; + user_is_me = 0; + while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u)) + if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) { + ++nloggedttys; + (void)strncpy(atty, u.ut_line, UT_LINESIZE); + atty[UT_LINESIZE] = '\0'; + if (term_chk(atty, &msgsok, &atime, 0)) + continue; /* bad term? skip */ + if (myuid && !msgsok) + continue; /* skip ttys with msgs off */ + if (strcmp(atty, mytty) == 0) { + user_is_me = 1; + continue; /* don't write to yourself */ + } + ++nttys; + if (atime > bestatime) { + bestatime = atime; + (void)strcpy(tty, atty); + } + } + + (void)close(ufd); + if (nloggedttys == 0) { + (void)fprintf(stderr, "write: %s is not logged in\n", user); + exit(1); + } + if (nttys == 0) { + if (user_is_me) { /* ok, so write to yourself! */ + (void)strcpy(tty, mytty); + return; + } + (void)fprintf(stderr, + "write: %s has messages disabled\n", user); + exit(1); + } else if (nttys > 1) { + (void)fprintf(stderr, + "write: %s is logged in more than once; writing to %s\n", + user, tty); + } +} + +/* + * term_chk - check that a terminal exists, and get the message bit + * and the access time + */ +term_chk(tty, msgsokP, atimeP, showerror) + char *tty; + int *msgsokP, showerror; + time_t *atimeP; +{ + struct stat s; + char path[MAXPATHLEN]; + + (void)sprintf(path, "/dev/%s", tty); + if (stat(path, &s) < 0) { + if (showerror) + (void)fprintf(stderr, + "write: %s: %s\n", path, strerror(errno)); + return(1); + } + *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */ + *atimeP = s.st_atime; + return(0); +} + +/* + * do_write - actually make the connection + */ +do_write(tty, mytty, myuid) + char *tty, *mytty; + uid_t myuid; +{ + register char *login, *nows; + register struct passwd *pwd; + time_t now, time(); + char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512]; + void done(); + + /* Determine our login name before the we reopen() stdout */ + if ((login = getlogin()) == NULL) + if (pwd = getpwuid(myuid)) + login = pwd->pw_name; + else + login = "???"; + + (void)sprintf(path, "/dev/%s", tty); + if ((freopen(path, "w", stdout)) == NULL) { + (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno)); + exit(1); + } + + (void)signal(SIGINT, done); + (void)signal(SIGHUP, done); + + /* print greeting */ + if (gethostname(host, sizeof(host)) < 0) + (void)strcpy(host, "???"); + now = time((time_t *)NULL); + nows = ctime(&now); + nows[16] = '\0'; + (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n", + login, host, mytty, nows + 11); + + while (fgets(line, sizeof(line), stdin) != NULL) + wr_fputs(line); +} + +/* + * done - cleanup and exit + */ +void +done() +{ + (void)printf("EOF\r\n"); + exit(0); +} + +/* + * wr_fputs - like fputs(), but makes control characters visible and + * turns \n into \r\n + */ +wr_fputs(s) + register char *s; +{ + register char c; + +#define PUTC(c) if (putchar(c) == EOF) goto err; + + for (; *s != '\0'; ++s) { + c = toascii(*s); + if (c == '\n') { + PUTC('\r'); + PUTC('\n'); + } else if (!isprint(c) && !isspace(c) && c != '\007') { + PUTC('^'); + PUTC(c^0x40); /* DEL to ?, others to alpha */ + } else + PUTC(c); + } + return; + +err: (void)fprintf(stderr, "write: %s\n", strerror(errno)); + exit(1); +#undef PUTC +} diff --git a/usr.bin/xargs/Makefile b/usr.bin/xargs/Makefile new file mode 100644 index 0000000..0bfb074 --- /dev/null +++ b/usr.bin/xargs/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= xargs + +.include diff --git a/usr.bin/xargs/pathnames.h b/usr.bin/xargs/pathnames.h new file mode 100644 index 0000000..3f05b3d --- /dev/null +++ b/usr.bin/xargs/pathnames.h @@ -0,0 +1,36 @@ +/*- + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_ECHO "/bin/echo" diff --git a/usr.bin/xargs/xargs.1 b/usr.bin/xargs/xargs.1 new file mode 100644 index 0000000..e703c43 --- /dev/null +++ b/usr.bin/xargs/xargs.1 @@ -0,0 +1,161 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" John B. Roll Jr. and the Institute of Electrical and Electronics +.\" Engineers, 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. +.\" +.\" @(#)xargs.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt XARGS 1 +.Os +.Sh NAME +.Nm xargs +.Nd "construct argument list(s) and execute utility" +.Sh SYNOPSIS +.Nm xargs +.Op Fl t +.Oo Op Fl x +.Fl n Ar number +.Oc +.Op Fl s Ar size +.Op Ar utility Op Ar arguments ... +.Sh DESCRIPTION +The +.Nm xargs +utility reads space, tab, newline and end-of-file delimited arguments +from the standard input and executes the specified +.Ar utility +with them as +arguments. +.Pp +The utility and any arguments specified on the command line are given +to the +.Ar utility +upon each invocation, followed by some number of the arguments read +from standard input. +The +.Ar utility +is repeatedly executed until standard input is exhausted. +.Pp +Spaces, tabs and newlines may be embedded in arguments using single +(``\ '\ '') +.Ek +or double (``"'') quotes or backslashes (``\e''). +Single quotes escape all non-single quote characters, excluding newlines, +up to the matching single quote. +Double quotes escape all non-double quote characters, excluding newlines, +up to the matching double quote. +Any single character, including newlines, may be escaped by a backslash. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl n Ar number +Set the maximum number of arguments taken from standard input for each +invocation of the utility. +An invocation of +.Ar utility +will use less than +.Ar number +standard input arguments if the number of bytes accumulated (see the +.Fl s +option) exceeds the specified +.Ar size +or there are fewer than +.Ar number +arguments remaining for the last invocation of +.Ar utility . +The current default value for +.Ar number +is 5000. +.It Fl s Ar size +Set the maximum number of bytes for the command line length provided to +.Ar utility . +The sum of the length of the utility name and the arguments passed to +.Ar utility +(including +.Dv NULL +terminators) will be less than or equal to this number. +The current default value for +.Ar size +is +.Dv ARG_MAX +- 2048. +.It Fl t +Echo the command to be executed to standard error immediately before it +is executed. +.It Fl x +Force +.Nm xargs +to terminate immediately if a command line containing +.Ar number +arguments will not fit in the specified (or default) command line length. +.El +.Pp +If no +.Ar utility +is specified, +.Xr echo 1 +is used. +.Pp +Undefined behavior may occur if +.Ar utility +reads from the standard input. +.Pp +The +.Nm xargs +utility exits immediately (without processing any further input) if a +command line cannot be assembled, +.Ar utility +cannot be invoked, an invocation of the utility is terminated by a signal +or an invocation of the utility exits with a value of 255. +.Pp +The +.Nm xargs +utility exits with a value of 0 if no error occurs. +If +.Ar utility +cannot be invoked, +.Nm xargs +exits with a value of 127. +If any other error occurs, +.Nm xargs +exits with a value of 1. +.Sh SEE ALSO +.Xr echo 1 , +.Xr find 1 +.Sh STANDARDS +The +.Nm xargs +utility is expected to be +.St -p1003.2 +compliant. diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c new file mode 100644 index 0000000..e28e840 --- /dev/null +++ b/usr.bin/xargs/xargs.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * John B. Roll Jr. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +int tflag, rval; + +void err __P((const char *, ...)); +void run __P((char **)); +void usage __P((void)); + +main(argc, argv) + int argc; + char **argv; +{ + register int ch; + register char *p, *bbp, *ebp, **bxp, **exp, **xp; + int cnt, indouble, insingle, nargs, nflag, nline, xflag; + char **av, *argp; + + /* + * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that + * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given + * that the smallest argument is 2 bytes in length, this means that + * the number of arguments is limited to: + * + * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2. + * + * We arbitrarily limit the number of arguments to 5000. This is + * allowed by POSIX.2 as long as the resulting minimum exec line is + * at least LINE_MAX. Realloc'ing as necessary is possible, but + * probably not worthwhile. + */ + nargs = 5000; + nline = ARG_MAX - 4 * 1024; + nflag = xflag = 0; + while ((ch = getopt(argc, argv, "n:s:tx")) != EOF) + switch(ch) { + case 'n': + nflag = 1; + if ((nargs = atoi(optarg)) <= 0) + err("illegal argument count"); + break; + case 's': + nline = atoi(optarg); + break; + case 't': + tflag = 1; + break; + case 'x': + xflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (xflag && !nflag) + usage(); + + /* + * Allocate pointers for the utility name, the utility arguments, + * the maximum arguments to be read from stdin and the trailing + * NULL. + */ + if (!(av = bxp = + malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) + err("%s", strerror(errno)); + + /* + * Use the user's name for the utility as argv[0], just like the + * shell. Echo is the default. Set up pointers for the user's + * arguments. + */ + if (!*argv) + cnt = strlen(*bxp++ = _PATH_ECHO); + else { + cnt = 0; + do { + cnt += strlen(*bxp++ = *argv) + 1; + } while (*++argv); + } + + /* + * Set up begin/end/traversing pointers into the array. The -n + * count doesn't include the trailing NULL pointer, so the malloc + * added in an extra slot. + */ + exp = (xp = bxp) + nargs; + + /* + * Allocate buffer space for the arguments read from stdin and the + * trailing NULL. Buffer space is defined as the default or specified + * space, minus the length of the utility name and arguments. Set up + * begin/end/traversing pointers into the array. The -s count does + * include the trailing NULL, so the malloc didn't add in an extra + * slot. + */ + nline -= cnt; + if (nline <= 0) + err("insufficient space for command"); + + if (!(bbp = malloc((u_int)nline + 1))) + err("%s", strerror(errno)); + ebp = (argp = p = bbp) + nline - 1; + + for (insingle = indouble = 0;;) + switch(ch = getchar()) { + case EOF: + /* No arguments since last exec. */ + if (p == bbp) + exit(rval); + + /* Nothing since end of last argument. */ + if (argp == p) { + *xp = NULL; + run(av); + exit(rval); + } + goto arg1; + case ' ': + case '\t': + /* Quotes escape tabs and spaces. */ + if (insingle || indouble) + goto addch; + goto arg2; + case '\n': + /* Empty lines are skipped. */ + if (argp == p) + continue; + + /* Quotes do not escape newlines. */ +arg1: if (insingle || indouble) + err("unterminated quote"); + +arg2: *p = '\0'; + *xp++ = argp; + + /* + * If max'd out on args or buffer, or reached EOF, + * run the command. If xflag and max'd out on buffer + * but not on args, object. + */ + if (xp == exp || p == ebp || ch == EOF) { + if (xflag && xp != exp && p == ebp) + err("insufficient space for arguments"); + *xp = NULL; + run(av); + if (ch == EOF) + exit(rval); + p = bbp; + xp = bxp; + } else + ++p; + argp = p; + break; + case '\'': + if (indouble) + goto addch; + insingle = !insingle; + break; + case '"': + if (insingle) + goto addch; + indouble = !indouble; + break; + case '\\': + /* Backslash escapes anything, is escaped by quotes. */ + if (!insingle && !indouble && (ch = getchar()) == EOF) + err("backslash at EOF"); + /* FALLTHROUGH */ + default: +addch: if (p < ebp) { + *p++ = ch; + break; + } + + /* If only one argument, not enough buffer space. */ + if (bxp == xp) + err("insufficient space for argument"); + /* Didn't hit argument limit, so if xflag object. */ + if (xflag) + err("insufficient space for arguments"); + + *xp = NULL; + run(av); + xp = bxp; + cnt = ebp - argp; + bcopy(argp, bbp, cnt); + p = (argp = bbp) + cnt; + *p++ = ch; + break; + } + /* NOTREACHED */ +} + +void +run(argv) + char **argv; +{ + volatile int noinvoke; + register char **p; + pid_t pid; + int status; + + if (tflag) { + (void)fprintf(stderr, "%s", *argv); + for (p = argv + 1; *p; ++p) + (void)fprintf(stderr, " %s", *p); + (void)fprintf(stderr, "\n"); + (void)fflush(stderr); + } + noinvoke = 0; + switch(pid = vfork()) { + case -1: + err("vfork: %s", strerror(errno)); + case 0: + execvp(argv[0], argv); + (void)fprintf(stderr, + "xargs: %s: %s\n", argv[0], strerror(errno)); + noinvoke = 1; + _exit(1); + } + pid = waitpid(pid, &status, 0); + if (pid == -1) + err("waitpid: %s", strerror(errno)); + /* If we couldn't invoke the utility, exit 127. */ + if (noinvoke) + exit(127); + /* If utility signaled or exited with a value of 255, exit 1-125. */ + if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) + exit(1); + if (WEXITSTATUS(status)) + rval = 1; +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: xargs [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "xargs: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/xinstall/Makefile b/usr.bin/xinstall/Makefile new file mode 100644 index 0000000..69de3ab --- /dev/null +++ b/usr.bin/xinstall/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= xinstall +SRCS= stat_flags.c xinstall.c +MAN1= install.0 +.PATH: ${.CURDIR}/../../bin/ls + +install: maninstall + install ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${PROG} ${DESTDIR}${BINDIR}/install + +.include diff --git a/usr.bin/xinstall/install.1 b/usr.bin/xinstall/install.1 new file mode 100644 index 0000000..c35c7a5 --- /dev/null +++ b/usr.bin/xinstall/install.1 @@ -0,0 +1,124 @@ +.\" Copyright (c) 1987, 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 the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)install.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt INSTALL 1 +.Os BSD 4.2 +.Sh NAME +.Nm install +.Nd install binaries +.Sh SYNOPSIS +.Nm install +.Op Fl cs +.Op Fl f Ar flags +.Op Fl g Ar group +.Op Fl m Ar mode +.Op Fl o Ar owner +.Ar file1 file2 +.Nm install +.Op Fl cs +.Op Fl f Ar flags +.Op Fl g Ar group +.Op Fl m Ar mode +.Op Fl o Ar owner +.Ar file1 +\&... +.Ar fileN directory +.Sh DESCRIPTION +The file(s) are moved (or copied if the +.Fl c +option is specified) to the target file or directory. +If the destination is a directory, then the +.Ar file +is moved into +.Ar directory +with its original filename. +If the target file already exists, it is overwritten if permissions +allow. +.Pp +.Bl -tag -width Ds +.It Fl c +Copy the file. +This flag turns off the default behavior of +.Nm install +where it deletes the original file after creating the target. +.It Fl f +Specify the target's file flags. +(See +.Xr chflags 1 +for a list of possible flags and their meanings.) +.It Fl g +Specify a group. +.It Fl m +Specify an alternate mode. +The default mode is set to rwxr-xr-x (0755). +The specified mode may be either an octal or symbolic value; see +.Xr chmod 1 +for a description of possible mode values. +.It Fl o +Specify an owner. +.It Fl s +.Nm Install +exec's the command +.Xr strip 1 +to strip binaries so that install can be portable over a large +number of systems and binary types. +.El +.Pp +By default, +.Nm install +preserves all file flags, with the exception of the ``nodump'' flag. +.Pp +The +.Nm install +utility attempts to prevent moving a file onto itself. +.Pp +Installing +.Pa /dev/null +creates an empty file. +.Pp +Upon successful completion a value of 0 is returned. +Otherwise, a value of 1 is returned. +.Sh SEE ALSO +.Xr chflags 1 , +.Xr chgrp 1 , +.Xr chmod 1 , +.Xr cp 1 , +.Xr mv 1 , +.Xr strip 1 , +.Xr chown 8 +.Sh HISTORY +The +.Nm install +utility appeared in +.Bx 4.2 . diff --git a/usr.bin/xinstall/pathnames.h b/usr.bin/xinstall/pathnames.h new file mode 100644 index 0000000..853b83c --- /dev/null +++ b/usr.bin/xinstall/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#define _PATH_STRIP "/usr/bin/strip" diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c new file mode 100644 index 0000000..4c41fa8 --- /dev/null +++ b/usr.bin/xinstall/xinstall.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +struct passwd *pp; +struct group *gp; +int docopy, dostrip; +int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; +char *group, *owner, pathbuf[MAXPATHLEN]; + +#define DIRECTORY 0x01 /* Tell install it's a directory. */ +#define SETFLAGS 0x02 /* Tell install to set flags. */ + +void copy __P((int, char *, int, char *, off_t)); +void err __P((const char *, ...)); +void install __P((char *, char *, u_long, u_int)); +u_long string_to_flags __P((char **, u_long *, u_long *)); +void strip __P((char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct stat from_sb, to_sb; + mode_t *set; + u_long fset; + u_int iflags; + int ch, no_target; + char *flags, *to_name; + + iflags = 0; + while ((ch = getopt(argc, argv, "cf:g:m:o:s")) != EOF) + switch((char)ch) { + case 'c': + docopy = 1; + break; + case 'f': + flags = optarg; + if (string_to_flags(&flags, &fset, NULL)) + err("%s: invalid flag", flags); + iflags |= SETFLAGS; + break; + case 'g': + group = optarg; + break; + case 'm': + if (!(set = setmode(optarg))) + err("%s: invalid file mode", optarg); + mode = getmode(set, 0); + break; + case 'o': + owner = optarg; + break; + case 's': + dostrip = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + if (argc < 2) + usage(); + + /* get group and owner id's */ + if (group && !(gp = getgrnam(group))) + err("unknown group %s", group); + if (owner && !(pp = getpwnam(owner))) + err("unknown user %s", owner); + + no_target = stat(to_name = argv[argc - 1], &to_sb); + if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) { + for (; *argv != to_name; ++argv) + install(*argv, to_name, fset, iflags | DIRECTORY); + exit(0); + } + + /* can't do file1 file2 directory/file */ + if (argc != 2) + usage(); + + if (!no_target) { + if (stat(*argv, &from_sb)) + err("%s: %s", *argv, strerror(errno)); + if (!S_ISREG(to_sb.st_mode)) + err("%s: %s", to_name, strerror(EFTYPE)); + if (to_sb.st_dev == from_sb.st_dev && + to_sb.st_ino == from_sb.st_ino) + err("%s and %s are the same file", *argv, to_name); + /* + * Unlink now... avoid ETXTBSY errors later. Try and turn + * off the append/immutable bits -- if we fail, go ahead, + * it might work. + */ +#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) + if (to_sb.st_flags & NOCHANGEBITS) + (void)chflags(to_name, + to_sb.st_flags & ~(NOCHANGEBITS)); + (void)unlink(to_name); + } + install(*argv, to_name, fset, iflags); + exit(0); +} + +/* + * install -- + * build a path name and install the file + */ +void +install(from_name, to_name, fset, flags) + char *from_name, *to_name; + u_long fset; + u_int flags; +{ + struct stat from_sb, to_sb; + int devnull, from_fd, to_fd, serrno; + char *p; + + /* If try to install NULL file to a directory, fails. */ + if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { + if (stat(from_name, &from_sb)) + err("%s: %s", from_name, strerror(errno)); + if (!S_ISREG(from_sb.st_mode)) + err("%s: %s", from_name, strerror(EFTYPE)); + /* Build the target path. */ + if (flags & DIRECTORY) { + (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s", + to_name, + (p = rindex(from_name, '/')) ? ++p : from_name); + to_name = pathbuf; + } + devnull = 0; + } else { + from_sb.st_flags = 0; /* XXX */ + devnull = 1; + } + + /* + * Unlink now... avoid ETXTBSY errors later. Try and turn + * off the append/immutable bits -- if we fail, go ahead, + * it might work. + */ + if (stat(to_name, &to_sb) == 0 && + to_sb.st_flags & (NOCHANGEBITS)) + (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS)); + (void)unlink(to_name); + + /* Create target. */ + if ((to_fd = open(to_name, + O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) + err("%s: %s", to_name, strerror(errno)); + if (!devnull) { + if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { + (void)unlink(to_name); + err("%s: %s", from_name, strerror(errno)); + } + copy(from_fd, from_name, to_fd, to_name, from_sb.st_size); + (void)close(from_fd); + } + if (dostrip) + strip(to_name); + /* + * Set owner, group, mode for target; do the chown first, + * chown may lose the setuid bits. + */ + if ((group || owner) && + fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1)) { + serrno = errno; + (void)unlink(to_name); + err("%s: chown/chgrp: %s", to_name, strerror(serrno)); + } + if (fchmod(to_fd, mode)) { + serrno = errno; + (void)unlink(to_name); + err("%s: chmod: %s", to_name, strerror(serrno)); + } + + /* + * If provided a set of flags, set them, otherwise, preserve the + * flags, except for the dump flag. + */ + if (fchflags(to_fd, + flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { + serrno = errno; + (void)unlink(to_name); + err("%s: chflags: %s", to_name, strerror(serrno)); + } + + (void)close(to_fd); + if (!docopy && !devnull && unlink(from_name)) + err("%s: %s", from_name, strerror(errno)); +} + +/* + * copy -- + * copy from one file to another + */ +void +copy(from_fd, from_name, to_fd, to_name, size) + register int from_fd, to_fd; + char *from_name, *to_name; + off_t size; +{ + register int nr, nw; + int serrno; + char *p, buf[MAXBSIZE]; + + /* + * Mmap and write if less than 8M (the limit is so we don't totally + * trash memory on big files. This is really a minor hack, but it + * wins some CPU back. + */ + if (size <= 8 * 1048576) { + if ((p = mmap(NULL, (size_t)size, PROT_READ, + 0, from_fd, (off_t)0)) == (char *)-1) + err("%s: %s", from_name, strerror(errno)); + if (write(to_fd, p, size) != size) + err("%s: %s", to_name, strerror(errno)); + } else { + while ((nr = read(from_fd, buf, sizeof(buf))) > 0) + if ((nw = write(to_fd, buf, nr)) != nr) { + serrno = errno; + (void)unlink(to_name); + err("%s: %s", + to_name, strerror(nw > 0 ? EIO : serrno)); + } + if (nr != 0) { + serrno = errno; + (void)unlink(to_name); + err("%s: %s", from_name, strerror(serrno)); + } + } +} + +/* + * strip -- + * use strip(1) to strip the target file + */ +void +strip(to_name) + char *to_name; +{ + int serrno, status; + + switch (vfork()) { + case -1: + serrno = errno; + (void)unlink(to_name); + err("forks: %s", strerror(errno)); + case 0: + execl(_PATH_STRIP, "strip", to_name, NULL); + err("%s: %s", _PATH_STRIP, strerror(errno)); + default: + if (wait(&status) == -1 || status) + (void)unlink(to_name); + } +} + +/* + * usage -- + * print a usage message and die + */ +void +usage() +{ + (void)fprintf(stderr, +"usage: install [-cs] [-f flags] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n"); + exit(1); +} + +#if __STDC__ +#include +#else +#include +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "install: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.bin/xstr/Makefile b/usr.bin/xstr/Makefile new file mode 100644 index 0000000..620a3ba --- /dev/null +++ b/usr.bin/xstr/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/9/93 + +PROG= xstr + +.include diff --git a/usr.bin/xstr/pathnames.h b/usr.bin/xstr/pathnames.h new file mode 100644 index 0000000..08a63dd --- /dev/null +++ b/usr.bin/xstr/pathnames.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 1989, 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/9/93 + */ + +#define _PATH_TMP "/tmp/xstrXXXXXX" diff --git a/usr.bin/xstr/xstr.1 b/usr.bin/xstr/xstr.1 new file mode 100644 index 0000000..8795a2d --- /dev/null +++ b/usr.bin/xstr/xstr.1 @@ -0,0 +1,159 @@ +.\" 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. +.\" +.\" @(#)xstr.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt XSTR 1 +.Os BSD 3 +.Sh NAME +.Nm xstr +.Nd "extract strings from C programs to implement shared strings" +.Sh SYNOPSIS +.Nm xstr +.Op Fl c +.Op Fl +.Op Ar file +.Sh DESCRIPTION +.Nm Xstr +maintains a file +.Pa strings +into which strings in component parts of a large program are hashed. +These strings are replaced with references to this common area. +This serves to implement shared constant strings, most useful if they +are also read-only. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl +.Nm Xstr +reads from the standard input. +.It Fl c +.Nm Xstr +will extract the strings from the C source +.Ar file +or the standard input +.Pq Fl , +replacing +string references by expressions of the form (&xstr[number]) +for some number. +An appropriate declaration of +.Nm xstr +is prepended to the file. +The resulting C text is placed in the file +.Pa x.c , +to then be compiled. +The strings from this file are placed in the +.Pa strings +data base if they are not there already. +Repeated strings and strings which are suffixes of existing strings +do not cause changes to the data base. +.El +.Pp +After all components of a large program have been compiled a file +.Pa xs.c +declaring the common +.Nm xstr +space can be created by a command of the form +.Bd -literal -offset indent +xstr +.Ed +.Pp +The file +.Pa xs.c +should then be compiled and loaded with the rest +of the program. +If possible, the array can be made read-only (shared) saving +space and swap overhead. +.Pp +.Nm Xstr +can also be used on a single file. +A command +.Bd -literal -offset indent +xstr name +.Ed +.Pp +creates files +.Pa x.c +and +.Pa xs.c +as before, without using or affecting any +.Pa strings +file in the same directory. +.Pp +It may be useful to run +.Nm xstr +after the C preprocessor if any macro definitions yield strings +or if there is conditional code which contains strings +which may not, in fact, be needed. +An appropriate command sequence for running +.Nm xstr +after the C preprocessor is: +.Pp +.Bd -literal -offset indent -compact +cc \-E name.c | xstr \-c \- +cc \-c x.c +mv x.o name.o +.Ed +.Pp +.Nm Xstr +does not touch the file +.Pa strings +unless new items are added, thus +.Xr make 1 +can avoid remaking +.Pa xs.o +unless truly necessary. +.Sh FILES +.Bl -tag -width /tmp/xsxx* -compact +.It Pa strings +Data base of strings +.It Pa x.c +Massaged C source +.It Pa xs.c +C source for definition of array `xstr' +.It Pa /tmp/xs* +Temp file when `xstr name' doesn't touch +.Pa strings +.El +.Sh SEE ALSO +.Xr mkstr 1 +.Sh BUGS +If a string is a suffix of another string in the data base, +but the shorter string is seen first by +.Nm xstr +both strings will be placed in the data base, when just +placing the longer one there will do. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/xstr/xstr.c b/usr.bin/xstr/xstr.c new file mode 100644 index 0000000..5f3d0ea --- /dev/null +++ b/usr.bin/xstr/xstr.c @@ -0,0 +1,471 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)xstr.c 8.1 (Berkeley) 6/9/93"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +/* + * xstr - extract and hash strings in a C program + * + * Bill Joy UCB + * November, 1978 + */ + +#define ignore(a) ((void) a) + +off_t tellpt; +off_t hashit(); +void onintr(); +char *savestr(); +off_t yankstr(); + +off_t mesgpt; +char *strings = "strings"; + +int cflg; +int vflg; +int readstd; + +main(argc, argv) + int argc; + char *argv[]; +{ + + argc--, argv++; + while (argc > 0 && argv[0][0] == '-') { + register char *cp = &(*argv++)[1]; + + argc--; + if (*cp == 0) { + readstd++; + continue; + } + do switch (*cp++) { + + case 'c': + cflg++; + continue; + + case 'v': + vflg++; + continue; + + default: + fprintf(stderr, "usage: xstr [ -v ] [ -c ] [ - ] [ name ... ]\n"); + } while (*cp); + } + if (signal(SIGINT, SIG_IGN) == SIG_DFL) + signal(SIGINT, onintr); + if (cflg || argc == 0 && !readstd) + inithash(); + else + strings = mktemp(strdup(_PATH_TMP)); + while (readstd || argc > 0) { + if (freopen("x.c", "w", stdout) == NULL) + perror("x.c"), exit(1); + if (!readstd && freopen(argv[0], "r", stdin) == NULL) + perror(argv[0]), exit(2); + process("x.c"); + if (readstd == 0) + argc--, argv++; + else + readstd = 0; + }; + flushsh(); + if (cflg == 0) + xsdotc(); + if (strings[0] == '/') + ignore(unlink(strings)); + exit(0); +} + +char linebuf[BUFSIZ]; + +process(name) + char *name; +{ + char *cp; + register int c; + register int incomm = 0; + int ret; + + printf("extern char\txstr[];\n"); + for (;;) { + if (fgets(linebuf, sizeof linebuf, stdin) == NULL) { + if (ferror(stdin)) { + perror(name); + exit(3); + } + break; + } + if (linebuf[0] == '#') { + if (linebuf[1] == ' ' && isdigit(linebuf[2])) + printf("#line%s", &linebuf[1]); + else + printf("%s", linebuf); + continue; + } + for (cp = linebuf; c = *cp++;) switch (c) { + + case '"': + if (incomm) + goto def; + if ((ret = (int) yankstr(&cp)) == -1) + goto out; + printf("(&xstr[%d])", ret); + break; + + case '\'': + if (incomm) + goto def; + putchar(c); + if (*cp) + putchar(*cp++); + break; + + case '/': + if (incomm || *cp != '*') + goto def; + incomm = 1; + cp++; + printf("/*"); + continue; + + case '*': + if (incomm && *cp == '/') { + incomm = 0; + cp++; + printf("*/"); + continue; + } + goto def; + +def: + default: + putchar(c); + break; + } + } +out: + if (ferror(stdout)) + perror("x.c"), onintr(); +} + +off_t +yankstr(cpp) + register char **cpp; +{ + register char *cp = *cpp; + register int c, ch; + char dbuf[BUFSIZ]; + register char *dp = dbuf; + register char *tp; + + while (c = *cp++) { + switch (c) { + + case '"': + cp++; + goto out; + + case '\\': + c = *cp++; + if (c == 0) + break; + if (c == '\n') { + if (fgets(linebuf, sizeof linebuf, stdin) + == NULL) { + if (ferror(stdin)) { + perror("x.c"); + exit(3); + } + return(-1); + } + cp = linebuf; + continue; + } + for (tp = "b\bt\tr\rn\nf\f\\\\\"\""; ch = *tp++; tp++) + if (c == ch) { + c = *tp; + goto gotc; + } + if (!octdigit(c)) { + *dp++ = '\\'; + break; + } + c -= '0'; + if (!octdigit(*cp)) + break; + c <<= 3, c += *cp++ - '0'; + if (!octdigit(*cp)) + break; + c <<= 3, c += *cp++ - '0'; + break; + } +gotc: + *dp++ = c; + } +out: + *cpp = --cp; + *dp = 0; + return (hashit(dbuf, 1)); +} + +octdigit(c) + char c; +{ + + return (isdigit(c) && c != '8' && c != '9'); +} + +inithash() +{ + char buf[BUFSIZ]; + register FILE *mesgread = fopen(strings, "r"); + + if (mesgread == NULL) + return; + for (;;) { + mesgpt = tellpt; + if (fgetNUL(buf, sizeof buf, mesgread) == NULL) + break; + ignore(hashit(buf, 0)); + } + ignore(fclose(mesgread)); +} + +fgetNUL(obuf, rmdr, file) + char *obuf; + register int rmdr; + FILE *file; +{ + register c; + register char *buf = obuf; + + while (--rmdr > 0 && (c = xgetc(file)) != 0 && c != EOF) + *buf++ = c; + *buf++ = 0; + return ((feof(file) || ferror(file)) ? NULL : 1); +} + +xgetc(file) + FILE *file; +{ + + tellpt++; + return (getc(file)); +} + +#define BUCKETS 128 + +struct hash { + off_t hpt; + char *hstr; + struct hash *hnext; + short hnew; +} bucket[BUCKETS]; + +off_t +hashit(str, new) + char *str; + int new; +{ + int i; + register struct hash *hp, *hp0; + + hp = hp0 = &bucket[lastchr(str) & 0177]; + while (hp->hnext) { + hp = hp->hnext; + i = istail(str, hp->hstr); + if (i >= 0) + return (hp->hpt + i); + } + if ((hp = (struct hash *) calloc(1, sizeof (*hp))) == NULL) { + perror("xstr"); + exit(8); + } + hp->hpt = mesgpt; + if (!(hp->hstr = strdup(str))) { + (void)fprintf(stderr, "xstr: %s\n", strerror(errno)); + exit(1); + } + mesgpt += strlen(hp->hstr) + 1; + hp->hnext = hp0->hnext; + hp->hnew = new; + hp0->hnext = hp; + return (hp->hpt); +} + +flushsh() +{ + register int i; + register struct hash *hp; + register FILE *mesgwrit; + register int old = 0, new = 0; + + for (i = 0; i < BUCKETS; i++) + for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) + if (hp->hnew) + new++; + else + old++; + if (new == 0 && old != 0) + return; + mesgwrit = fopen(strings, old ? "r+" : "w"); + if (mesgwrit == NULL) + perror(strings), exit(4); + for (i = 0; i < BUCKETS; i++) + for (hp = bucket[i].hnext; hp != NULL; hp = hp->hnext) { + found(hp->hnew, hp->hpt, hp->hstr); + if (hp->hnew) { + fseek(mesgwrit, hp->hpt, 0); + ignore(fwrite(hp->hstr, strlen(hp->hstr) + 1, 1, mesgwrit)); + if (ferror(mesgwrit)) + perror(strings), exit(4); + } + } + if (fclose(mesgwrit) == EOF) + perror(strings), exit(4); +} + +found(new, off, str) + int new; + off_t off; + char *str; +{ + if (vflg == 0) + return; + if (!new) + fprintf(stderr, "found at %d:", (int) off); + else + fprintf(stderr, "new at %d:", (int) off); + prstr(str); + fprintf(stderr, "\n"); +} + +prstr(cp) + register char *cp; +{ + register int c; + + while (c = (*cp++ & 0377)) + if (c < ' ') + fprintf(stderr, "^%c", c + '`'); + else if (c == 0177) + fprintf(stderr, "^?"); + else if (c > 0200) + fprintf(stderr, "\\%03o", c); + else + fprintf(stderr, "%c", c); +} + +xsdotc() +{ + register FILE *strf = fopen(strings, "r"); + register FILE *xdotcf; + + if (strf == NULL) + perror(strings), exit(5); + xdotcf = fopen("xs.c", "w"); + if (xdotcf == NULL) + perror("xs.c"), exit(6); + fprintf(xdotcf, "char\txstr[] = {\n"); + for (;;) { + register int i, c; + + for (i = 0; i < 8; i++) { + c = getc(strf); + if (ferror(strf)) { + perror(strings); + onintr(); + } + if (feof(strf)) { + fprintf(xdotcf, "\n"); + goto out; + } + fprintf(xdotcf, "0x%02x,", c); + } + fprintf(xdotcf, "\n"); + } +out: + fprintf(xdotcf, "};\n"); + ignore(fclose(xdotcf)); + ignore(fclose(strf)); +} + +lastchr(cp) + register char *cp; +{ + + while (cp[0] && cp[1]) + cp++; + return (*cp); +} + +istail(str, of) + register char *str, *of; +{ + register int d = strlen(of) - strlen(str); + + if (d < 0 || strcmp(&of[d], str) != 0) + return (-1); + return (d); +} + +void +onintr() +{ + + ignore(signal(SIGINT, SIG_IGN)); + if (strings[0] == '/') + ignore(unlink(strings)); + ignore(unlink("x.c")); + ignore(unlink("xs.c")); + exit(7); +} diff --git a/usr.bin/yacc/ACKNOWLEDGEMENTS b/usr.bin/yacc/ACKNOWLEDGEMENTS new file mode 100644 index 0000000..b66bb25 --- /dev/null +++ b/usr.bin/yacc/ACKNOWLEDGEMENTS @@ -0,0 +1,25 @@ + Berkeley Yacc owes much to the unflagging efforts of Keith Bostic. +His badgering kept me working on it long after I was ready to quit. + + Berkeley Yacc is based on the excellent algorithm for computing LALR(1) +lookaheads developed by Tom Pennello and Frank DeRemer. The algorithm is +described in their almost impenetrable article in TOPLAS 4,4. + + Finally, much of the credit for the latest version must go to those +who pointed out deficiencies of my earlier releases. Among the most +prolific contributors were + + Benson I. Margulies + Dave Gentzel + Antoine Verheijen + Peter S. Housel + Dale Smith + Ozan Yigit + John Campbell + Bill Sommerfeld + Paul Hilfinger + Gary Bridgewater + Dave Bakken + Dan Lanciani + Richard Sargent + Parag Patel diff --git a/usr.bin/yacc/Makefile b/usr.bin/yacc/Makefile new file mode 100644 index 0000000..71633a3 --- /dev/null +++ b/usr.bin/yacc/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 5.3 (Berkeley) 5/12/90 + +PROG= yacc +SRCS= closure.c error.c lalr.c lr0.c main.c mkpar.c output.c reader.c \ + skeleton.c symtab.c verbose.c warshall.c +MAN1= yacc.0 yyfix.0 + +beforeinstall: + install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/yyfix.sh ${DESTDIR}${BINDIR}/yyfix + +.include diff --git a/usr.bin/yacc/NEW_FEATURES b/usr.bin/yacc/NEW_FEATURES new file mode 100644 index 0000000..b030c62 --- /dev/null +++ b/usr.bin/yacc/NEW_FEATURES @@ -0,0 +1,46 @@ + The -r option has been implemented. The -r option tells Yacc to +put the read-only tables in y.tab.c and the code and variables in +y.code.c. Keith Bostic asked for this option so that :yyfix could be +eliminated. + + The -l and -t options have been implemented. The -l option tells +Yacc not to include #line directives in the code it produces. The -t +option causes debugging code to be included in the compiled parser. + + The code for error recovery has been changed to implement the same +algorithm as AT&T Yacc. There will still be differences in the way +error recovery works because AT&T Yacc uses more default reductions +than Berkeley Yacc. + + The environment variable TMPDIR determines the directory where +temporary files will be created. If TMPDIR is defined, temporary files +will be created in the directory whose pathname is the value of TMPDIR. +By default, temporary files are created in /tmp. + + The keywords are now case-insensitive. For example, %nonassoc, +%NONASSOC, %NonAssoc, and %nOnAsSoC are all equivalent. + + Commas and semicolons that are not part of C code are treated as +commentary. + + Line-end comments, as in BCPL, are permitted. Line-end comments +begin with // and end at the next end-of-line. Line-end comments are +permitted in C code; they are converted to C comments on output. + + The form of y.output files has been changed to look more like +those produced by AT&T Yacc. + + A new kind of declaration has been added. The form of the declaration +is + + %ident string + +where string is a sequence of characters begining with a double quote +and ending with either a double quote or the next end-of-line, whichever +comes first. The declaration will cause a #ident directive to be written +near the start of the output file. + + If a parser has been compiled with debugging code, that code can be +enabled by setting an environment variable. If the environment variable +YYDEBUG is set to 0, debugging output is suppressed. If it is set to 1, +debugging output is written to standard output. diff --git a/usr.bin/yacc/NOTES b/usr.bin/yacc/NOTES new file mode 100644 index 0000000..9db3c96 --- /dev/null +++ b/usr.bin/yacc/NOTES @@ -0,0 +1,9 @@ +Berkeley Yacc reflects its origins. The reason so many routines +use exactly six register variables is that Berkeley Yacc was +developed on a VAX using PCC. PCC placed at most six variables +in registers. I went to considerable effort to find which six +variables most belonged in registers. Changes in machines and +compilers make that effort worthless, perhaps even harmful. + +The code contains many instances where address calculations are +performed in particular ways to optimize the code for the VAX. diff --git a/usr.bin/yacc/README b/usr.bin/yacc/README new file mode 100644 index 0000000..091f233 --- /dev/null +++ b/usr.bin/yacc/README @@ -0,0 +1,23 @@ + Berkeley Yacc is an LALR(1) parser generator. Berkeley Yacc has been made +as compatible as possible with AT&T Yacc. Berkeley Yacc can accept any input +specification that conforms to the AT&T Yacc documentation. Specifications +that take advantage of undocumented features of AT&T Yacc will probably be +rejected. + + Berkeley Yacc is distributed with no warranty whatever. The code is certain +to contain errors. Neither the author nor any contributor takes responsibility +for any consequences of its use. + + Berkeley Yacc is in the public domain. The data structures and algorithms +used in Berkeley Yacc are all either taken from documents available to the +general public or are inventions of the author. Anyone may freely distribute +source or binary forms of Berkeley Yacc whether unchanged or modified. +Distributers may charge whatever fees they can obtain for Berkeley Yacc. +Programs generated by Berkeley Yacc may be distributed freely. + + Please report bugs to + + robert.corbett@eng.Sun.COM + +Include a small example if possible. Please include the banner string from +skeleton.c with the bug report. Do not expect rapid responses. diff --git a/usr.bin/yacc/closure.c b/usr.bin/yacc/closure.c new file mode 100644 index 0000000..5f63c5f --- /dev/null +++ b/usr.bin/yacc/closure.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)closure.c 5.3 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +short *itemset; +short *itemsetend; +unsigned *ruleset; + +static unsigned *first_derives; +static unsigned *EFF; + + +set_EFF() +{ + register unsigned *row; + register int symbol; + register short *sp; + register int rowsize; + register int i; + register int rule; + + rowsize = WORDSIZE(nvars); + EFF = NEW2(nvars * rowsize, unsigned); + + row = EFF; + for (i = start_symbol; i < nsyms; i++) + { + sp = derives[i]; + for (rule = *sp; rule > 0; rule = *++sp) + { + symbol = ritem[rrhs[rule]]; + if (ISVAR(symbol)) + { + symbol -= start_symbol; + SETBIT(row, symbol); + } + } + row += rowsize; + } + + reflexive_transitive_closure(EFF, nvars); + +#ifdef DEBUG + print_EFF(); +#endif +} + + +set_first_derives() +{ + register unsigned *rrow; + register unsigned *vrow; + register int j; + register unsigned k; + register unsigned cword; + register short *rp; + + int rule; + int i; + int rulesetsize; + int varsetsize; + + rulesetsize = WORDSIZE(nrules); + varsetsize = WORDSIZE(nvars); + first_derives = NEW2(nvars * rulesetsize, unsigned) - ntokens * rulesetsize; + + set_EFF(); + + rrow = first_derives + ntokens * rulesetsize; + for (i = start_symbol; i < nsyms; i++) + { + vrow = EFF + ((i - ntokens) * varsetsize); + k = BITS_PER_WORD; + for (j = start_symbol; j < nsyms; k++, j++) + { + if (k >= BITS_PER_WORD) + { + cword = *vrow++; + k = 0; + } + + if (cword & (1 << k)) + { + rp = derives[j]; + while ((rule = *rp++) >= 0) + { + SETBIT(rrow, rule); + } + } + } + + vrow += varsetsize; + rrow += rulesetsize; + } + +#ifdef DEBUG + print_first_derives(); +#endif + + FREE(EFF); +} + + +closure(nucleus, n) +short *nucleus; +int n; +{ + register int ruleno; + register unsigned word; + register unsigned i; + register short *csp; + register unsigned *dsp; + register unsigned *rsp; + register int rulesetsize; + + short *csend; + unsigned *rsend; + int symbol; + int itemno; + + rulesetsize = WORDSIZE(nrules); + rsp = ruleset; + rsend = ruleset + rulesetsize; + for (rsp = ruleset; rsp < rsend; rsp++) + *rsp = 0; + + csend = nucleus + n; + for (csp = nucleus; csp < csend; ++csp) + { + symbol = ritem[*csp]; + if (ISVAR(symbol)) + { + dsp = first_derives + symbol * rulesetsize; + rsp = ruleset; + while (rsp < rsend) + *rsp++ |= *dsp++; + } + } + + ruleno = 0; + itemsetend = itemset; + csp = nucleus; + for (rsp = ruleset; rsp < rsend; ++rsp) + { + word = *rsp; + if (word) + { + for (i = 0; i < BITS_PER_WORD; ++i) + { + if (word & (1 << i)) + { + itemno = rrhs[ruleno+i]; + while (csp < csend && *csp < itemno) + *itemsetend++ = *csp++; + *itemsetend++ = itemno; + while (csp < csend && *csp == itemno) + ++csp; + } + } + } + ruleno += BITS_PER_WORD; + } + + while (csp < csend) + *itemsetend++ = *csp++; + +#ifdef DEBUG + print_closure(n); +#endif +} + + + +finalize_closure() +{ + FREE(itemset); + FREE(ruleset); + FREE(first_derives + ntokens * WORDSIZE(nrules)); +} + + +#ifdef DEBUG + +print_closure(n) +int n; +{ + register short *isp; + + printf("\n\nn = %d\n\n", n); + for (isp = itemset; isp < itemsetend; isp++) + printf(" %d\n", *isp); +} + + +print_EFF() +{ + register int i, j; + register unsigned *rowp; + register unsigned word; + register unsigned k; + + printf("\n\nEpsilon Free Firsts\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("\n%s", symbol_name[i]); + rowp = EFF + ((i - start_symbol) * WORDSIZE(nvars)); + word = *rowp++; + + k = BITS_PER_WORD; + for (j = 0; j < nvars; k++, j++) + { + if (k >= BITS_PER_WORD) + { + word = *rowp++; + k = 0; + } + + if (word & (1 << k)) + printf(" %s", symbol_name[start_symbol + j]); + } + } +} + + +print_first_derives() +{ + register int i; + register int j; + register unsigned *rp; + register unsigned cword; + register unsigned k; + + printf("\n\n\nFirst Derives\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("\n%s derives\n", symbol_name[i]); + rp = first_derives + i * WORDSIZE(nrules); + k = BITS_PER_WORD; + for (j = 0; j <= nrules; k++, j++) + { + if (k >= BITS_PER_WORD) + { + cword = *rp++; + k = 0; + } + + if (cword & (1 << k)) + printf(" %d\n", j); + } + } + + fflush(stdout); +} + +#endif diff --git a/usr.bin/yacc/defs.h b/usr.bin/yacc/defs.h new file mode 100644 index 0000000..e5e96d2 --- /dev/null +++ b/usr.bin/yacc/defs.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)defs.h 5.6 (Berkeley) 5/24/93 + */ + +#include +#include +#include + + +/* machine-dependent definitions */ +/* the following definitions are for the Tahoe */ +/* they might have to be changed for other machines */ + +/* MAXCHAR is the largest unsigned character value */ +/* MAXSHORT is the largest value of a C short */ +/* MINSHORT is the most negative value of a C short */ +/* MAXTABLE is the maximum table size */ +/* BITS_PER_WORD is the number of bits in a C unsigned */ +/* WORDSIZE computes the number of words needed to */ +/* store n bits */ +/* BIT returns the value of the n-th bit starting */ +/* from r (0-indexed) */ +/* SETBIT sets the n-th bit starting from r */ + +#define MAXCHAR 255 +#define MAXSHORT 32767 +#define MINSHORT -32768 +#define MAXTABLE 32500 +#define BITS_PER_WORD 32 +#define WORDSIZE(n) (((n)+(BITS_PER_WORD-1))/BITS_PER_WORD) +#define BIT(r, n) ((((r)[(n)>>5])>>((n)&31))&1) +#define SETBIT(r, n) ((r)[(n)>>5]|=((unsigned)1<<((n)&31))) + + +/* character names */ + +#define NUL '\0' /* the null character */ +#define NEWLINE '\n' /* line feed */ +#define SP ' ' /* space */ +#define BS '\b' /* backspace */ +#define HT '\t' /* horizontal tab */ +#define VT '\013' /* vertical tab */ +#define CR '\r' /* carriage return */ +#define FF '\f' /* form feed */ +#define QUOTE '\'' /* single quote */ +#define DOUBLE_QUOTE '\"' /* double quote */ +#define BACKSLASH '\\' /* backslash */ + + +/* defines for constructing filenames */ + +#define CODE_SUFFIX ".code.c" +#define DEFINES_SUFFIX ".tab.h" +#define OUTPUT_SUFFIX ".tab.c" +#define VERBOSE_SUFFIX ".output" + + +/* keyword codes */ + +#define TOKEN 0 +#define LEFT 1 +#define RIGHT 2 +#define NONASSOC 3 +#define MARK 4 +#define TEXT 5 +#define TYPE 6 +#define START 7 +#define UNION 8 +#define IDENT 9 + + +/* symbol classes */ + +#define UNKNOWN 0 +#define TERM 1 +#define NONTERM 2 + + +/* the undefined value */ + +#define UNDEFINED (-1) + + +/* action codes */ + +#define SHIFT 1 +#define REDUCE 2 + + +/* character macros */ + +#define IS_IDENT(c) (isalnum(c) || (c) == '_' || (c) == '.' || (c) == '$') +#define IS_OCTAL(c) ((c) >= '0' && (c) <= '7') +#define NUMERIC_VALUE(c) ((c) - '0') + + +/* symbol macros */ + +#define ISTOKEN(s) ((s) < start_symbol) +#define ISVAR(s) ((s) >= start_symbol) + + +/* storage allocation macros */ + +#define CALLOC(k,n) (calloc((unsigned)(k),(unsigned)(n))) +#define FREE(x) (free((char*)(x))) +#define MALLOC(n) (malloc((unsigned)(n))) +#define NEW(t) ((t*)allocate(sizeof(t))) +#define NEW2(n,t) ((t*)allocate((unsigned)((n)*sizeof(t)))) +#define REALLOC(p,n) (realloc((char*)(p),(unsigned)(n))) + + +/* the structure of a symbol table entry */ + +typedef struct bucket bucket; +struct bucket +{ + struct bucket *link; + struct bucket *next; + char *name; + char *tag; + short value; + short index; + short prec; + char class; + char assoc; +}; + + +/* the structure of the LR(0) state machine */ + +typedef struct core core; +struct core +{ + struct core *next; + struct core *link; + short number; + short accessing_symbol; + short nitems; + short items[1]; +}; + + +/* the structure used to record shifts */ + +typedef struct shifts shifts; +struct shifts +{ + struct shifts *next; + short number; + short nshifts; + short shift[1]; +}; + + +/* the structure used to store reductions */ + +typedef struct reductions reductions; +struct reductions +{ + struct reductions *next; + short number; + short nreds; + short rules[1]; +}; + + +/* the structure used to represent parser actions */ + +typedef struct action action; +struct action +{ + struct action *next; + short symbol; + short number; + short prec; + char action_code; + char assoc; + char suppressed; +}; + + +/* global variables */ + +extern char dflag; +extern char lflag; +extern char rflag; +extern char tflag; +extern char vflag; +extern char *symbol_prefix; + +extern char *myname; +extern char *cptr; +extern char *line; +extern int lineno; +extern int outline; + +extern char *banner[]; +extern char *tables[]; +extern char *header[]; +extern char *body[]; +extern char *trailer[]; + +extern char *action_file_name; +extern char *code_file_name; +extern char *defines_file_name; +extern char *input_file_name; +extern char *output_file_name; +extern char *text_file_name; +extern char *union_file_name; +extern char *verbose_file_name; + +extern FILE *action_file; +extern FILE *code_file; +extern FILE *defines_file; +extern FILE *input_file; +extern FILE *output_file; +extern FILE *text_file; +extern FILE *union_file; +extern FILE *verbose_file; + +extern int nitems; +extern int nrules; +extern int nsyms; +extern int ntokens; +extern int nvars; +extern int ntags; + +extern char unionized; +extern char line_format[]; + +extern int start_symbol; +extern char **symbol_name; +extern short *symbol_value; +extern short *symbol_prec; +extern char *symbol_assoc; + +extern short *ritem; +extern short *rlhs; +extern short *rrhs; +extern short *rprec; +extern char *rassoc; + +extern short **derives; +extern char *nullable; + +extern bucket *first_symbol; +extern bucket *last_symbol; + +extern int nstates; +extern core *first_state; +extern shifts *first_shift; +extern reductions *first_reduction; +extern short *accessing_symbol; +extern core **state_table; +extern shifts **shift_table; +extern reductions **reduction_table; +extern unsigned *LA; +extern short *LAruleno; +extern short *lookaheads; +extern short *goto_map; +extern short *from_state; +extern short *to_state; + +extern action **parser; +extern int SRtotal; +extern int RRtotal; +extern short *SRconflicts; +extern short *RRconflicts; +extern short *defred; +extern short *rules_used; +extern short nunused; +extern short final_state; + +/* global functions */ + +extern char *allocate(); +extern bucket *lookup(); +extern bucket *make_bucket(); + + +/* system variables */ + +extern int errno; + + +/* system functions */ + +extern void free(); +extern char *calloc(); +extern char *malloc(); +extern char *realloc(); +extern char *strcpy(); diff --git a/usr.bin/yacc/error.c b/usr.bin/yacc/error.c new file mode 100644 index 0000000..54a49ad --- /dev/null +++ b/usr.bin/yacc/error.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)error.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +/* routines for printing error messages */ + +#include "defs.h" + + +fatal(msg) +char *msg; +{ + fprintf(stderr, "%s: f - %s\n", myname, msg); + done(2); +} + + +no_space() +{ + fprintf(stderr, "%s: f - out of space\n", myname); + done(2); +} + + +open_error(filename) +char *filename; +{ + fprintf(stderr, "%s: f - cannot open \"%s\"\n", myname, filename); + done(2); +} + + +unexpected_EOF() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unexpected end-of-file\n", + myname, lineno, input_file_name); + done(1); +} + + +print_pos(st_line, st_cptr) +char *st_line; +char *st_cptr; +{ + register char *s; + + if (st_line == 0) return; + for (s = st_line; *s != '\n'; ++s) + { + if (isprint(*s) || *s == '\t') + putc(*s, stderr); + else + putc('?', stderr); + } + putc('\n', stderr); + for (s = st_line; s < st_cptr; ++s) + { + if (*s == '\t') + putc('\t', stderr); + else + putc(' ', stderr); + } + putc('^', stderr); + putc('\n', stderr); +} + + +syntax_error(st_lineno, st_line, st_cptr) +int st_lineno; +char *st_line; +char *st_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", syntax error\n", + myname, st_lineno, input_file_name); + print_pos(st_line, st_cptr); + done(1); +} + + +unterminated_comment(c_lineno, c_line, c_cptr) +int c_lineno; +char *c_line; +char *c_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unmatched /*\n", + myname, c_lineno, input_file_name); + print_pos(c_line, c_cptr); + done(1); +} + + +unterminated_string(s_lineno, s_line, s_cptr) +int s_lineno; +char *s_line; +char *s_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated string\n", + myname, s_lineno, input_file_name); + print_pos(s_line, s_cptr); + done(1); +} + + +unterminated_text(t_lineno, t_line, t_cptr) +int t_lineno; +char *t_line; +char *t_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unmatched %%{\n", + myname, t_lineno, input_file_name); + print_pos(t_line, t_cptr); + done(1); +} + + +unterminated_union(u_lineno, u_line, u_cptr) +int u_lineno; +char *u_line; +char *u_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated %%union \ +declaration\n", myname, u_lineno, input_file_name); + print_pos(u_line, u_cptr); + done(1); +} + + +over_unionized(u_cptr) +char *u_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", too many %%union \ +declarations\n", myname, lineno, input_file_name); + print_pos(line, u_cptr); + done(1); +} + + +illegal_tag(t_lineno, t_line, t_cptr) +int t_lineno; +char *t_line; +char *t_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal tag\n", + myname, t_lineno, input_file_name); + print_pos(t_line, t_cptr); + done(1); +} + + +illegal_character(c_cptr) +char *c_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal character\n", + myname, lineno, input_file_name); + print_pos(line, c_cptr); + done(1); +} + + +used_reserved(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal use of reserved symbol \ +%s\n", myname, lineno, input_file_name, s); + done(1); +} + + +tokenized_start(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s cannot be \ +declared to be a token\n", myname, lineno, input_file_name, s); + done(1); +} + + +retyped_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the type of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +reprec_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the precedence of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +revalued_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the value of %s has been \ +redeclared\n", myname, lineno, input_file_name, s); +} + + +terminal_start(s) +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", the start symbol %s is a \ +token\n", myname, lineno, input_file_name, s); + done(1); +} + + +restarted_warning() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the start symbol has been \ +redeclared\n", myname, lineno, input_file_name); +} + + +no_grammar() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", no grammar has been \ +specified\n", myname, lineno, input_file_name); + done(1); +} + + +terminal_lhs(s_lineno) +int s_lineno; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", a token appears on the lhs \ +of a production\n", myname, s_lineno, input_file_name); + done(1); +} + + +prec_redeclared() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", conflicting %%prec \ +specifiers\n", myname, lineno, input_file_name); +} + + +unterminated_action(a_lineno, a_line, a_cptr) +int a_lineno; +char *a_line; +char *a_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", unterminated action\n", + myname, a_lineno, input_file_name); + print_pos(a_line, a_cptr); + done(1); +} + + +dollar_warning(a_lineno, i) +int a_lineno; +int i; +{ + fprintf(stderr, "%s: w - line %d of \"%s\", $%d references beyond the \ +end of the current rule\n", myname, a_lineno, input_file_name, i); +} + + +dollar_error(a_lineno, a_line, a_cptr) +int a_lineno; +char *a_line; +char *a_cptr; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", illegal $-name\n", + myname, a_lineno, input_file_name); + print_pos(a_line, a_cptr); + done(1); +} + + +untyped_lhs() +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $$ is untyped\n", + myname, lineno, input_file_name); + done(1); +} + + +untyped_rhs(i, s) +int i; +char *s; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $%d (%s) is untyped\n", + myname, lineno, input_file_name, i, s); + done(1); +} + + +unknown_rhs(i) +int i; +{ + fprintf(stderr, "%s: e - line %d of \"%s\", $%d is untyped\n", + myname, lineno, input_file_name, i); + done(1); +} + + +default_action_warning() +{ + fprintf(stderr, "%s: w - line %d of \"%s\", the default action assigns an \ +undefined value to $$\n", myname, lineno, input_file_name); +} + + +undefined_goal(s) +char *s; +{ + fprintf(stderr, "%s: e - the start symbol %s is undefined\n", myname, s); + done(1); +} + + +undefined_symbol_warning(s) +char *s; +{ + fprintf(stderr, "%s: w - the symbol %s is undefined\n", myname, s); +} diff --git a/usr.bin/yacc/lalr.c b/usr.bin/yacc/lalr.c new file mode 100644 index 0000000..bf9aec8 --- /dev/null +++ b/usr.bin/yacc/lalr.c @@ -0,0 +1,678 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lalr.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "defs.h" + +typedef + struct shorts + { + struct shorts *next; + short value; + } + shorts; + +int tokensetsize; +short *lookaheads; +short *LAruleno; +unsigned *LA; +short *accessing_symbol; +core **state_table; +shifts **shift_table; +reductions **reduction_table; +short *goto_map; +short *from_state; +short *to_state; + +short **transpose(); + +static int infinity; +static int maxrhs; +static int ngotos; +static unsigned *F; +static short **includes; +static shorts **lookback; +static short **R; +static short *INDEX; +static short *VERTICES; +static int top; + + +lalr() +{ + tokensetsize = WORDSIZE(ntokens); + + set_state_table(); + set_accessing_symbol(); + set_shift_table(); + set_reduction_table(); + set_maxrhs(); + initialize_LA(); + set_goto_map(); + initialize_F(); + build_relations(); + compute_FOLLOWS(); + compute_lookaheads(); +} + + + +set_state_table() +{ + register core *sp; + + state_table = NEW2(nstates, core *); + for (sp = first_state; sp; sp = sp->next) + state_table[sp->number] = sp; +} + + + +set_accessing_symbol() +{ + register core *sp; + + accessing_symbol = NEW2(nstates, short); + for (sp = first_state; sp; sp = sp->next) + accessing_symbol[sp->number] = sp->accessing_symbol; +} + + + +set_shift_table() +{ + register shifts *sp; + + shift_table = NEW2(nstates, shifts *); + for (sp = first_shift; sp; sp = sp->next) + shift_table[sp->number] = sp; +} + + + +set_reduction_table() +{ + register reductions *rp; + + reduction_table = NEW2(nstates, reductions *); + for (rp = first_reduction; rp; rp = rp->next) + reduction_table[rp->number] = rp; +} + + + +set_maxrhs() +{ + register short *itemp; + register short *item_end; + register int length; + register int max; + + length = 0; + max = 0; + item_end = ritem + nitems; + for (itemp = ritem; itemp < item_end; itemp++) + { + if (*itemp >= 0) + { + length++; + } + else + { + if (length > max) max = length; + length = 0; + } + } + + maxrhs = max; +} + + + +initialize_LA() +{ + register int i, j, k; + register reductions *rp; + + lookaheads = NEW2(nstates + 1, short); + + k = 0; + for (i = 0; i < nstates; i++) + { + lookaheads[i] = k; + rp = reduction_table[i]; + if (rp) + k += rp->nreds; + } + lookaheads[nstates] = k; + + LA = NEW2(k * tokensetsize, unsigned); + LAruleno = NEW2(k, short); + lookback = NEW2(k, shorts *); + + k = 0; + for (i = 0; i < nstates; i++) + { + rp = reduction_table[i]; + if (rp) + { + for (j = 0; j < rp->nreds; j++) + { + LAruleno[k] = rp->rules[j]; + k++; + } + } + } +} + + +set_goto_map() +{ + register shifts *sp; + register int i; + register int symbol; + register int k; + register short *temp_map; + register int state2; + register int state1; + + goto_map = NEW2(nvars + 1, short) - ntokens; + temp_map = NEW2(nvars + 1, short) - ntokens; + + ngotos = 0; + for (sp = first_shift; sp; sp = sp->next) + { + for (i = sp->nshifts - 1; i >= 0; i--) + { + symbol = accessing_symbol[sp->shift[i]]; + + if (ISTOKEN(symbol)) break; + + if (ngotos == MAXSHORT) + fatal("too many gotos"); + + ngotos++; + goto_map[symbol]++; + } + } + + k = 0; + for (i = ntokens; i < nsyms; i++) + { + temp_map[i] = k; + k += goto_map[i]; + } + + for (i = ntokens; i < nsyms; i++) + goto_map[i] = temp_map[i]; + + goto_map[nsyms] = ngotos; + temp_map[nsyms] = ngotos; + + from_state = NEW2(ngotos, short); + to_state = NEW2(ngotos, short); + + for (sp = first_shift; sp; sp = sp->next) + { + state1 = sp->number; + for (i = sp->nshifts - 1; i >= 0; i--) + { + state2 = sp->shift[i]; + symbol = accessing_symbol[state2]; + + if (ISTOKEN(symbol)) break; + + k = temp_map[symbol]++; + from_state[k] = state1; + to_state[k] = state2; + } + } + + FREE(temp_map + ntokens); +} + + + +/* Map_goto maps a state/symbol pair into its numeric representation. */ + +int +map_goto(state, symbol) +int state; +int symbol; +{ + register int high; + register int low; + register int middle; + register int s; + + low = goto_map[symbol]; + high = goto_map[symbol + 1]; + + for (;;) + { + assert(low <= high); + middle = (low + high) >> 1; + s = from_state[middle]; + if (s == state) + return (middle); + else if (s < state) + low = middle + 1; + else + high = middle - 1; + } +} + + + +initialize_F() +{ + register int i; + register int j; + register int k; + register shifts *sp; + register short *edge; + register unsigned *rowp; + register short *rp; + register short **reads; + register int nedges; + register int stateno; + register int symbol; + register int nwords; + + nwords = ngotos * tokensetsize; + F = NEW2(nwords, unsigned); + + reads = NEW2(ngotos, short *); + edge = NEW2(ngotos + 1, short); + nedges = 0; + + rowp = F; + for (i = 0; i < ngotos; i++) + { + stateno = to_state[i]; + sp = shift_table[stateno]; + + if (sp) + { + k = sp->nshifts; + + for (j = 0; j < k; j++) + { + symbol = accessing_symbol[sp->shift[j]]; + if (ISVAR(symbol)) + break; + SETBIT(rowp, symbol); + } + + for (; j < k; j++) + { + symbol = accessing_symbol[sp->shift[j]]; + if (nullable[symbol]) + edge[nedges++] = map_goto(stateno, symbol); + } + + if (nedges) + { + reads[i] = rp = NEW2(nedges + 1, short); + + for (j = 0; j < nedges; j++) + rp[j] = edge[j]; + + rp[nedges] = -1; + nedges = 0; + } + } + + rowp += tokensetsize; + } + + SETBIT(F, 0); + digraph(reads); + + for (i = 0; i < ngotos; i++) + { + if (reads[i]) + FREE(reads[i]); + } + + FREE(reads); + FREE(edge); +} + + + +build_relations() +{ + register int i; + register int j; + register int k; + register short *rulep; + register short *rp; + register shifts *sp; + register int length; + register int nedges; + register int done; + register int state1; + register int stateno; + register int symbol1; + register int symbol2; + register short *shortp; + register short *edge; + register short *states; + register short **new_includes; + + includes = NEW2(ngotos, short *); + edge = NEW2(ngotos + 1, short); + states = NEW2(maxrhs + 1, short); + + for (i = 0; i < ngotos; i++) + { + nedges = 0; + state1 = from_state[i]; + symbol1 = accessing_symbol[to_state[i]]; + + for (rulep = derives[symbol1]; *rulep >= 0; rulep++) + { + length = 1; + states[0] = state1; + stateno = state1; + + for (rp = ritem + rrhs[*rulep]; *rp >= 0; rp++) + { + symbol2 = *rp; + sp = shift_table[stateno]; + k = sp->nshifts; + + for (j = 0; j < k; j++) + { + stateno = sp->shift[j]; + if (accessing_symbol[stateno] == symbol2) break; + } + + states[length++] = stateno; + } + + add_lookback_edge(stateno, *rulep, i); + + length--; + done = 0; + while (!done) + { + done = 1; + rp--; + if (ISVAR(*rp)) + { + stateno = states[--length]; + edge[nedges++] = map_goto(stateno, *rp); + if (nullable[*rp] && length > 0) done = 0; + } + } + } + + if (nedges) + { + includes[i] = shortp = NEW2(nedges + 1, short); + for (j = 0; j < nedges; j++) + shortp[j] = edge[j]; + shortp[nedges] = -1; + } + } + + new_includes = transpose(includes, ngotos); + + for (i = 0; i < ngotos; i++) + if (includes[i]) + FREE(includes[i]); + + FREE(includes); + + includes = new_includes; + + FREE(edge); + FREE(states); +} + + +add_lookback_edge(stateno, ruleno, gotono) +int stateno, ruleno, gotono; +{ + register int i, k; + register int found; + register shorts *sp; + + i = lookaheads[stateno]; + k = lookaheads[stateno + 1]; + found = 0; + while (!found && i < k) + { + if (LAruleno[i] == ruleno) + found = 1; + else + ++i; + } + assert(found); + + sp = NEW(shorts); + sp->next = lookback[i]; + sp->value = gotono; + lookback[i] = sp; +} + + + +short ** +transpose(R, n) +short **R; +int n; +{ + register short **new_R; + register short **temp_R; + register short *nedges; + register short *sp; + register int i; + register int k; + + nedges = NEW2(n, short); + + for (i = 0; i < n; i++) + { + sp = R[i]; + if (sp) + { + while (*sp >= 0) + nedges[*sp++]++; + } + } + + new_R = NEW2(n, short *); + temp_R = NEW2(n, short *); + + for (i = 0; i < n; i++) + { + k = nedges[i]; + if (k > 0) + { + sp = NEW2(k + 1, short); + new_R[i] = sp; + temp_R[i] = sp; + sp[k] = -1; + } + } + + FREE(nedges); + + for (i = 0; i < n; i++) + { + sp = R[i]; + if (sp) + { + while (*sp >= 0) + *temp_R[*sp++]++ = i; + } + } + + FREE(temp_R); + + return (new_R); +} + + + +compute_FOLLOWS() +{ + digraph(includes); +} + + +compute_lookaheads() +{ + register int i, n; + register unsigned *fp1, *fp2, *fp3; + register shorts *sp, *next; + register unsigned *rowp; + + rowp = LA; + n = lookaheads[nstates]; + for (i = 0; i < n; i++) + { + fp3 = rowp + tokensetsize; + for (sp = lookback[i]; sp; sp = sp->next) + { + fp1 = rowp; + fp2 = F + tokensetsize * sp->value; + while (fp1 < fp3) + *fp1++ |= *fp2++; + } + rowp = fp3; + } + + for (i = 0; i < n; i++) + for (sp = lookback[i]; sp; sp = next) + { + next = sp->next; + FREE(sp); + } + + FREE(lookback); + FREE(F); +} + + +digraph(relation) +short **relation; +{ + register int i; + + infinity = ngotos + 2; + INDEX = NEW2(ngotos + 1, short); + VERTICES = NEW2(ngotos + 1, short); + top = 0; + + R = relation; + + for (i = 0; i < ngotos; i++) + INDEX[i] = 0; + + for (i = 0; i < ngotos; i++) + { + if (INDEX[i] == 0 && R[i]) + traverse(i); + } + + FREE(INDEX); + FREE(VERTICES); +} + + + +traverse(i) +register int i; +{ + register unsigned *fp1; + register unsigned *fp2; + register unsigned *fp3; + register int j; + register short *rp; + + int height; + unsigned *base; + + VERTICES[++top] = i; + INDEX[i] = height = top; + + base = F + i * tokensetsize; + fp3 = base + tokensetsize; + + rp = R[i]; + if (rp) + { + while ((j = *rp++) >= 0) + { + if (INDEX[j] == 0) + traverse(j); + + if (INDEX[i] > INDEX[j]) + INDEX[i] = INDEX[j]; + + fp1 = base; + fp2 = F + j * tokensetsize; + + while (fp1 < fp3) + *fp1++ |= *fp2++; + } + } + + if (INDEX[i] == height) + { + for (;;) + { + j = VERTICES[top--]; + INDEX[j] = infinity; + + if (i == j) + break; + + fp1 = base; + fp2 = F + j * tokensetsize; + + while (fp1 < fp3) + *fp2++ = *fp1++; + } + } +} diff --git a/usr.bin/yacc/lr0.c b/usr.bin/yacc/lr0.c new file mode 100644 index 0000000..43106ea --- /dev/null +++ b/usr.bin/yacc/lr0.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)lr0.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +extern short *itemset; +extern short *itemsetend; +extern unsigned *ruleset; + +int nstates; +core *first_state; +shifts *first_shift; +reductions *first_reduction; + +int get_state(); +core *new_state(); + +static core **state_set; +static core *this_state; +static core *last_state; +static shifts *last_shift; +static reductions *last_reduction; + +static int nshifts; +static short *shift_symbol; + +static short *redset; +static short *shiftset; + +static short **kernel_base; +static short **kernel_end; +static short *kernel_items; + + +allocate_itemsets() +{ + register short *itemp; + register short *item_end; + register int symbol; + register int i; + register int count; + register int max; + register short *symbol_count; + + count = 0; + symbol_count = NEW2(nsyms, short); + + item_end = ritem + nitems; + for (itemp = ritem; itemp < item_end; itemp++) + { + symbol = *itemp; + if (symbol >= 0) + { + count++; + symbol_count[symbol]++; + } + } + + kernel_base = NEW2(nsyms, short *); + kernel_items = NEW2(count, short); + + count = 0; + max = 0; + for (i = 0; i < nsyms; i++) + { + kernel_base[i] = kernel_items + count; + count += symbol_count[i]; + if (max < symbol_count[i]) + max = symbol_count[i]; + } + + shift_symbol = symbol_count; + kernel_end = NEW2(nsyms, short *); +} + + +allocate_storage() +{ + allocate_itemsets(); + shiftset = NEW2(nsyms, short); + redset = NEW2(nrules + 1, short); + state_set = NEW2(nitems, core *); +} + + +append_states() +{ + register int i; + register int j; + register int symbol; + +#ifdef TRACE + fprintf(stderr, "Entering append_states()\n"); +#endif + for (i = 1; i < nshifts; i++) + { + symbol = shift_symbol[i]; + j = i; + while (j > 0 && shift_symbol[j - 1] > symbol) + { + shift_symbol[j] = shift_symbol[j - 1]; + j--; + } + shift_symbol[j] = symbol; + } + + for (i = 0; i < nshifts; i++) + { + symbol = shift_symbol[i]; + shiftset[i] = get_state(symbol); + } +} + + +free_storage() +{ + FREE(shift_symbol); + FREE(redset); + FREE(shiftset); + FREE(kernel_base); + FREE(kernel_end); + FREE(kernel_items); + FREE(state_set); +} + + + +generate_states() +{ + allocate_storage(); + itemset = NEW2(nitems, short); + ruleset = NEW2(WORDSIZE(nrules), unsigned); + set_first_derives(); + initialize_states(); + + while (this_state) + { + closure(this_state->items, this_state->nitems); + save_reductions(); + new_itemsets(); + append_states(); + + if (nshifts > 0) + save_shifts(); + + this_state = this_state->next; + } + + finalize_closure(); + free_storage(); +} + + + +int +get_state(symbol) +int symbol; +{ + register int key; + register short *isp1; + register short *isp2; + register short *iend; + register core *sp; + register int found; + register int n; + +#ifdef TRACE + fprintf(stderr, "Entering get_state(%d)\n", symbol); +#endif + + isp1 = kernel_base[symbol]; + iend = kernel_end[symbol]; + n = iend - isp1; + + key = *isp1; + assert(0 <= key && key < nitems); + sp = state_set[key]; + if (sp) + { + found = 0; + while (!found) + { + if (sp->nitems == n) + { + found = 1; + isp1 = kernel_base[symbol]; + isp2 = sp->items; + + while (found && isp1 < iend) + { + if (*isp1++ != *isp2++) + found = 0; + } + } + + if (!found) + { + if (sp->link) + { + sp = sp->link; + } + else + { + sp = sp->link = new_state(symbol); + found = 1; + } + } + } + } + else + { + state_set[key] = sp = new_state(symbol); + } + + return (sp->number); +} + + + +initialize_states() +{ + register int i; + register short *start_derives; + register core *p; + + start_derives = derives[start_symbol]; + for (i = 0; start_derives[i] >= 0; ++i) + continue; + + p = (core *) MALLOC(sizeof(core) + i*sizeof(short)); + if (p == 0) no_space(); + + p->next = 0; + p->link = 0; + p->number = 0; + p->accessing_symbol = 0; + p->nitems = i; + + for (i = 0; start_derives[i] >= 0; ++i) + p->items[i] = rrhs[start_derives[i]]; + + first_state = last_state = this_state = p; + nstates = 1; +} + + +new_itemsets() +{ + register int i; + register int shiftcount; + register short *isp; + register short *ksp; + register int symbol; + + for (i = 0; i < nsyms; i++) + kernel_end[i] = 0; + + shiftcount = 0; + isp = itemset; + while (isp < itemsetend) + { + i = *isp++; + symbol = ritem[i]; + if (symbol > 0) + { + ksp = kernel_end[symbol]; + if (!ksp) + { + shift_symbol[shiftcount++] = symbol; + ksp = kernel_base[symbol]; + } + + *ksp++ = i + 1; + kernel_end[symbol] = ksp; + } + } + + nshifts = shiftcount; +} + + + +core * +new_state(symbol) +int symbol; +{ + register int n; + register core *p; + register short *isp1; + register short *isp2; + register short *iend; + +#ifdef TRACE + fprintf(stderr, "Entering new_state(%d)\n", symbol); +#endif + + if (nstates >= MAXSHORT) + fatal("too many states"); + + isp1 = kernel_base[symbol]; + iend = kernel_end[symbol]; + n = iend - isp1; + + p = (core *) allocate((unsigned) (sizeof(core) + (n - 1) * sizeof(short))); + p->accessing_symbol = symbol; + p->number = nstates; + p->nitems = n; + + isp2 = p->items; + while (isp1 < iend) + *isp2++ = *isp1++; + + last_state->next = p; + last_state = p; + + nstates++; + + return (p); +} + + +/* show_cores is used for debugging */ + +show_cores() +{ + core *p; + int i, j, k, n; + int itemno; + + k = 0; + for (p = first_state; p; ++k, p = p->next) + { + if (k) printf("\n"); + printf("state %d, number = %d, accessing symbol = %s\n", + k, p->number, symbol_name[p->accessing_symbol]); + n = p->nitems; + for (i = 0; i < n; ++i) + { + itemno = p->items[i]; + printf("%4d ", itemno); + j = itemno; + while (ritem[j] >= 0) ++j; + printf("%s :", symbol_name[rlhs[-ritem[j]]]); + j = rrhs[-ritem[j]]; + while (j < itemno) + printf(" %s", symbol_name[ritem[j++]]); + printf(" ."); + while (ritem[j] >= 0) + printf(" %s", symbol_name[ritem[j++]]); + printf("\n"); + fflush(stdout); + } + } +} + + +/* show_ritems is used for debugging */ + +show_ritems() +{ + int i; + + for (i = 0; i < nitems; ++i) + printf("ritem[%d] = %d\n", i, ritem[i]); +} + + +/* show_rrhs is used for debugging */ +show_rrhs() +{ + int i; + + for (i = 0; i < nrules; ++i) + printf("rrhs[%d] = %d\n", i, rrhs[i]); +} + + +/* show_shifts is used for debugging */ + +show_shifts() +{ + shifts *p; + int i, j, k; + + k = 0; + for (p = first_shift; p; ++k, p = p->next) + { + if (k) printf("\n"); + printf("shift %d, number = %d, nshifts = %d\n", k, p->number, + p->nshifts); + j = p->nshifts; + for (i = 0; i < j; ++i) + printf("\t%d\n", p->shift[i]); + } +} + + +save_shifts() +{ + register shifts *p; + register short *sp1; + register short *sp2; + register short *send; + + p = (shifts *) allocate((unsigned) (sizeof(shifts) + + (nshifts - 1) * sizeof(short))); + + p->number = this_state->number; + p->nshifts = nshifts; + + sp1 = shiftset; + sp2 = p->shift; + send = shiftset + nshifts; + + while (sp1 < send) + *sp2++ = *sp1++; + + if (last_shift) + { + last_shift->next = p; + last_shift = p; + } + else + { + first_shift = p; + last_shift = p; + } +} + + + +save_reductions() +{ + register short *isp; + register short *rp1; + register short *rp2; + register int item; + register int count; + register reductions *p; + register short *rend; + + count = 0; + for (isp = itemset; isp < itemsetend; isp++) + { + item = ritem[*isp]; + if (item < 0) + { + redset[count++] = -item; + } + } + + if (count) + { + p = (reductions *) allocate((unsigned) (sizeof(reductions) + + (count - 1) * sizeof(short))); + + p->number = this_state->number; + p->nreds = count; + + rp1 = redset; + rp2 = p->rules; + rend = rp1 + count; + + while (rp1 < rend) + *rp2++ = *rp1++; + + if (last_reduction) + { + last_reduction->next = p; + last_reduction = p; + } + else + { + first_reduction = p; + last_reduction = p; + } + } +} + + +set_derives() +{ + register int i, k; + register int lhs; + register short *rules; + + derives = NEW2(nsyms, short *); + rules = NEW2(nvars + nrules, short); + + k = 0; + for (lhs = start_symbol; lhs < nsyms; lhs++) + { + derives[lhs] = rules + k; + for (i = 0; i < nrules; i++) + { + if (rlhs[i] == lhs) + { + rules[k] = i; + k++; + } + } + rules[k] = -1; + k++; + } + +#ifdef DEBUG + print_derives(); +#endif +} + +free_derives() +{ + FREE(derives[start_symbol]); + FREE(derives); +} + +#ifdef DEBUG +print_derives() +{ + register int i; + register short *sp; + + printf("\nDERIVES\n\n"); + + for (i = start_symbol; i < nsyms; i++) + { + printf("%s derives ", symbol_name[i]); + for (sp = derives[i]; *sp >= 0; sp++) + { + printf(" %d", *sp); + } + putchar('\n'); + } + + putchar('\n'); +} +#endif + + +set_nullable() +{ + register int i, j; + register int empty; + int done; + + nullable = MALLOC(nsyms); + if (nullable == 0) no_space(); + + for (i = 0; i < nsyms; ++i) + nullable[i] = 0; + + done = 0; + while (!done) + { + done = 1; + for (i = 1; i < nitems; i++) + { + empty = 1; + while ((j = ritem[i]) >= 0) + { + if (!nullable[j]) + empty = 0; + ++i; + } + if (empty) + { + j = rlhs[-j]; + if (!nullable[j]) + { + nullable[j] = 1; + done = 0; + } + } + } + } + +#ifdef DEBUG + for (i = 0; i < nsyms; i++) + { + if (nullable[i]) + printf("%s is nullable\n", symbol_name[i]); + else + printf("%s is not nullable\n", symbol_name[i]); + } +#endif +} + + +free_nullable() +{ + FREE(nullable); +} + + +lr0() +{ + set_derives(); + set_nullable(); + generate_states(); +} diff --git a/usr.bin/yacc/main.c b/usr.bin/yacc/main.c new file mode 100644 index 0000000..79b332a --- /dev/null +++ b/usr.bin/yacc/main.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)main.c 5.5 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include +#include "defs.h" + +char dflag; +char lflag; +char rflag; +char tflag; +char vflag; + +char *symbol_prefix; +char *file_prefix = "y"; +char *myname = "yacc"; +char *temp_form = "yacc.XXXXXXX"; + +int lineno; +int outline; + +char *action_file_name; +char *code_file_name; +char *defines_file_name; +char *input_file_name = ""; +char *output_file_name; +char *text_file_name; +char *union_file_name; +char *verbose_file_name; + +FILE *action_file; /* a temp file, used to save actions associated */ + /* with rules until the parser is written */ +FILE *code_file; /* y.code.c (used when the -r option is specified) */ +FILE *defines_file; /* y.tab.h */ +FILE *input_file; /* the input file */ +FILE *output_file; /* y.tab.c */ +FILE *text_file; /* a temp file, used to save text until all */ + /* symbols have been defined */ +FILE *union_file; /* a temp file, used to save the union */ + /* definition until all symbol have been */ + /* defined */ +FILE *verbose_file; /* y.output */ + +int nitems; +int nrules; +int nsyms; +int ntokens; +int nvars; + +int start_symbol; +char **symbol_name; +short *symbol_value; +short *symbol_prec; +char *symbol_assoc; + +short *ritem; +short *rlhs; +short *rrhs; +short *rprec; +char *rassoc; +short **derives; +char *nullable; + +extern char *mktemp(); +extern char *getenv(); + + +done(k) +int k; +{ + if (action_file) { fclose(action_file); unlink(action_file_name); } + if (text_file) { fclose(text_file); unlink(text_file_name); } + if (union_file) { fclose(union_file); unlink(union_file_name); } + exit(k); +} + + +void +onintr(signo) + int signo; +{ + done(1); +} + + +set_signals() +{ +#ifdef SIGINT + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); +#endif +#ifdef SIGTERM + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, onintr); +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, onintr); +#endif +} + + +usage() +{ + fprintf(stderr, "usage: %s [-dlrtv] [-b file_prefix] [-p symbol_prefix] filename\n", myname); + exit(1); +} + + +getargs(argc, argv) +int argc; +char *argv[]; +{ + register int i; + register char *s; + + if (argc > 0) myname = argv[0]; + for (i = 1; i < argc; ++i) + { + s = argv[i]; + if (*s != '-') break; + switch (*++s) + { + case '\0': + input_file = stdin; + if (i + 1 < argc) usage(); + return; + + case '-': + ++i; + goto no_more_options; + + case 'b': + if (*++s) + file_prefix = s; + else if (++i < argc) + file_prefix = argv[i]; + else + usage(); + continue; + + case 'd': + dflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'p': + if (*++s) + symbol_prefix = s; + else if (++i < argc) + symbol_prefix = argv[i]; + else + usage(); + continue; + + case 'r': + rflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + default: + usage(); + } + + for (;;) + { + switch (*++s) + { + case '\0': + goto end_of_option; + + case 'd': + dflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'r': + rflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + default: + usage(); + } + } +end_of_option:; + } + +no_more_options:; + if (i + 1 != argc) usage(); + input_file_name = argv[i]; +} + + +char * +allocate(n) +unsigned n; +{ + register char *p; + + p = NULL; + if (n) + { + p = CALLOC(1, n); + if (!p) no_space(); + } + return (p); +} + + +create_file_names() +{ + int i, len; + char *tmpdir; + + tmpdir = getenv("TMPDIR"); + if (tmpdir == 0) tmpdir = "/tmp"; + + len = strlen(tmpdir); + i = len + 13; + if (len && tmpdir[len-1] != '/') + ++i; + + action_file_name = MALLOC(i); + if (action_file_name == 0) no_space(); + text_file_name = MALLOC(i); + if (text_file_name == 0) no_space(); + union_file_name = MALLOC(i); + if (union_file_name == 0) no_space(); + + strcpy(action_file_name, tmpdir); + strcpy(text_file_name, tmpdir); + strcpy(union_file_name, tmpdir); + + if (len && tmpdir[len - 1] != '/') + { + action_file_name[len] = '/'; + text_file_name[len] = '/'; + union_file_name[len] = '/'; + ++len; + } + + strcpy(action_file_name + len, temp_form); + strcpy(text_file_name + len, temp_form); + strcpy(union_file_name + len, temp_form); + + action_file_name[len + 5] = 'a'; + text_file_name[len + 5] = 't'; + union_file_name[len + 5] = 'u'; + + mktemp(action_file_name); + mktemp(text_file_name); + mktemp(union_file_name); + + len = strlen(file_prefix); + + output_file_name = MALLOC(len + 7); + if (output_file_name == 0) + no_space(); + strcpy(output_file_name, file_prefix); + strcpy(output_file_name + len, OUTPUT_SUFFIX); + + if (rflag) + { + code_file_name = MALLOC(len + 8); + if (code_file_name == 0) + no_space(); + strcpy(code_file_name, file_prefix); + strcpy(code_file_name + len, CODE_SUFFIX); + } + else + code_file_name = output_file_name; + + if (dflag) + { + defines_file_name = MALLOC(len + 7); + if (defines_file_name == 0) + no_space(); + strcpy(defines_file_name, file_prefix); + strcpy(defines_file_name + len, DEFINES_SUFFIX); + } + + if (vflag) + { + verbose_file_name = MALLOC(len + 8); + if (verbose_file_name == 0) + no_space(); + strcpy(verbose_file_name, file_prefix); + strcpy(verbose_file_name + len, VERBOSE_SUFFIX); + } +} + + +open_files() +{ + create_file_names(); + + if (input_file == 0) + { + input_file = fopen(input_file_name, "r"); + if (input_file == 0) + open_error(input_file_name); + } + + action_file = fopen(action_file_name, "w"); + if (action_file == 0) + open_error(action_file_name); + + text_file = fopen(text_file_name, "w"); + if (text_file == 0) + open_error(text_file_name); + + if (vflag) + { + verbose_file = fopen(verbose_file_name, "w"); + if (verbose_file == 0) + open_error(verbose_file_name); + } + + if (dflag) + { + defines_file = fopen(defines_file_name, "w"); + if (defines_file == 0) + open_error(defines_file_name); + union_file = fopen(union_file_name, "w"); + if (union_file == 0) + open_error(union_file_name); + } + + output_file = fopen(output_file_name, "w"); + if (output_file == 0) + open_error(output_file_name); + + if (rflag) + { + code_file = fopen(code_file_name, "w"); + if (code_file == 0) + open_error(code_file_name); + } + else + code_file = output_file; +} + + +int +main(argc, argv) +int argc; +char *argv[]; +{ + set_signals(); + getargs(argc, argv); + open_files(); + reader(); + lr0(); + lalr(); + make_parser(); + verbose(); + output(); + done(0); + /*NOTREACHED*/ +} diff --git a/usr.bin/yacc/mkpar.c b/usr.bin/yacc/mkpar.c new file mode 100644 index 0000000..42ead14 --- /dev/null +++ b/usr.bin/yacc/mkpar.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)mkpar.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +action **parser; +int SRtotal; +int RRtotal; +short *SRconflicts; +short *RRconflicts; +short *defred; +short *rules_used; +short nunused; +short final_state; + +static int SRcount; +static int RRcount; + +extern action *parse_actions(); +extern action *get_shifts(); +extern action *add_reductions(); +extern action *add_reduce(); + + +make_parser() +{ + register int i; + + parser = NEW2(nstates, action *); + for (i = 0; i < nstates; i++) + parser[i] = parse_actions(i); + + find_final_state(); + remove_conflicts(); + unused_rules(); + if (SRtotal + RRtotal > 0) total_conflicts(); + defreds(); +} + + +action * +parse_actions(stateno) +register int stateno; +{ + register action *actions; + + actions = get_shifts(stateno); + actions = add_reductions(stateno, actions); + return (actions); +} + + +action * +get_shifts(stateno) +int stateno; +{ + register action *actions, *temp; + register shifts *sp; + register short *to_state; + register int i, k; + register int symbol; + + actions = 0; + sp = shift_table[stateno]; + if (sp) + { + to_state = sp->shift; + for (i = sp->nshifts - 1; i >= 0; i--) + { + k = to_state[i]; + symbol = accessing_symbol[k]; + if (ISTOKEN(symbol)) + { + temp = NEW(action); + temp->next = actions; + temp->symbol = symbol; + temp->number = k; + temp->prec = symbol_prec[symbol]; + temp->action_code = SHIFT; + temp->assoc = symbol_assoc[symbol]; + actions = temp; + } + } + } + return (actions); +} + +action * +add_reductions(stateno, actions) +int stateno; +register action *actions; +{ + register int i, j, m, n; + register int ruleno, tokensetsize; + register unsigned *rowp; + + tokensetsize = WORDSIZE(ntokens); + m = lookaheads[stateno]; + n = lookaheads[stateno + 1]; + for (i = m; i < n; i++) + { + ruleno = LAruleno[i]; + rowp = LA + i * tokensetsize; + for (j = ntokens - 1; j >= 0; j--) + { + if (BIT(rowp, j)) + actions = add_reduce(actions, ruleno, j); + } + } + return (actions); +} + + +action * +add_reduce(actions, ruleno, symbol) +register action *actions; +register int ruleno, symbol; +{ + register action *temp, *prev, *next; + + prev = 0; + for (next = actions; next && next->symbol < symbol; next = next->next) + prev = next; + + while (next && next->symbol == symbol && next->action_code == SHIFT) + { + prev = next; + next = next->next; + } + + while (next && next->symbol == symbol && + next->action_code == REDUCE && next->number < ruleno) + { + prev = next; + next = next->next; + } + + temp = NEW(action); + temp->next = next; + temp->symbol = symbol; + temp->number = ruleno; + temp->prec = rprec[ruleno]; + temp->action_code = REDUCE; + temp->assoc = rassoc[ruleno]; + + if (prev) + prev->next = temp; + else + actions = temp; + + return (actions); +} + + +find_final_state() +{ + register int goal, i; + register short *to_state; + register shifts *p; + + p = shift_table[0]; + to_state = p->shift; + goal = ritem[1]; + for (i = p->nshifts - 1; i >= 0; --i) + { + final_state = to_state[i]; + if (accessing_symbol[final_state] == goal) break; + } +} + + +unused_rules() +{ + register int i; + register action *p; + + rules_used = (short *) MALLOC(nrules*sizeof(short)); + if (rules_used == 0) no_space(); + + for (i = 0; i < nrules; ++i) + rules_used[i] = 0; + + for (i = 0; i < nstates; ++i) + { + for (p = parser[i]; p; p = p->next) + { + if (p->action_code == REDUCE && p->suppressed == 0) + rules_used[p->number] = 1; + } + } + + nunused = 0; + for (i = 3; i < nrules; ++i) + if (!rules_used[i]) ++nunused; + + if (nunused) + if (nunused == 1) + fprintf(stderr, "%s: 1 rule never reduced\n", myname); + else + fprintf(stderr, "%s: %d rules never reduced\n", myname, nunused); +} + + +remove_conflicts() +{ + register int i; + register int symbol; + register action *p, *pref; + + SRtotal = 0; + RRtotal = 0; + SRconflicts = NEW2(nstates, short); + RRconflicts = NEW2(nstates, short); + for (i = 0; i < nstates; i++) + { + SRcount = 0; + RRcount = 0; + symbol = -1; + for (p = parser[i]; p; p = p->next) + { + if (p->symbol != symbol) + { + pref = p; + symbol = p->symbol; + } + else if (i == final_state && symbol == 0) + { + SRcount++; + p->suppressed = 1; + } + else if (pref->action_code == SHIFT) + { + if (pref->prec > 0 && p->prec > 0) + { + if (pref->prec < p->prec) + { + pref->suppressed = 2; + pref = p; + } + else if (pref->prec > p->prec) + { + p->suppressed = 2; + } + else if (pref->assoc == LEFT) + { + pref->suppressed = 2; + pref = p; + } + else if (pref->assoc == RIGHT) + { + p->suppressed = 2; + } + else + { + pref->suppressed = 2; + p->suppressed = 2; + } + } + else + { + SRcount++; + p->suppressed = 1; + } + } + else + { + RRcount++; + p->suppressed = 1; + } + } + SRtotal += SRcount; + RRtotal += RRcount; + SRconflicts[i] = SRcount; + RRconflicts[i] = RRcount; + } +} + + +total_conflicts() +{ + fprintf(stderr, "%s: ", myname); + if (SRtotal == 1) + fprintf(stderr, "1 shift/reduce conflict"); + else if (SRtotal > 1) + fprintf(stderr, "%d shift/reduce conflicts", SRtotal); + + if (SRtotal && RRtotal) + fprintf(stderr, ", "); + + if (RRtotal == 1) + fprintf(stderr, "1 reduce/reduce conflict"); + else if (RRtotal > 1) + fprintf(stderr, "%d reduce/reduce conflicts", RRtotal); + + fprintf(stderr, ".\n"); +} + + +int +sole_reduction(stateno) +int stateno; +{ + register int count, ruleno; + register action *p; + + count = 0; + ruleno = 0; + for (p = parser[stateno]; p; p = p->next) + { + if (p->action_code == SHIFT && p->suppressed == 0) + return (0); + else if (p->action_code == REDUCE && p->suppressed == 0) + { + if (ruleno > 0 && p->number != ruleno) + return (0); + if (p->symbol != 1) + ++count; + ruleno = p->number; + } + } + + if (count == 0) + return (0); + return (ruleno); +} + + +defreds() +{ + register int i; + + defred = NEW2(nstates, short); + for (i = 0; i < nstates; i++) + defred[i] = sole_reduction(i); +} + +free_action_row(p) +register action *p; +{ + register action *q; + + while (p) + { + q = p->next; + FREE(p); + p = q; + } +} + +free_parser() +{ + register int i; + + for (i = 0; i < nstates; i++) + free_action_row(parser[i]); + + FREE(parser); +} diff --git a/usr.bin/yacc/output.c b/usr.bin/yacc/output.c new file mode 100644 index 0000000..f8fd1c5 --- /dev/null +++ b/usr.bin/yacc/output.c @@ -0,0 +1,1250 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)output.c 5.7 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +static int nvectors; +static int nentries; +static short **froms; +static short **tos; +static short *tally; +static short *width; +static short *state_count; +static short *order; +static short *base; +static short *pos; +static int maxtable; +static short *table; +static short *check; +static int lowzero; +static int high; + + +output() +{ + free_itemsets(); + free_shifts(); + free_reductions(); + output_prefix(); + output_stored_text(); + output_defines(); + output_rule_data(); + output_yydefred(); + output_actions(); + free_parser(); + output_debug(); + output_stype(); + if (rflag) write_section(tables); + write_section(header); + output_trailing_text(); + write_section(body); + output_semantic_actions(); + write_section(trailer); +} + + +output_prefix() +{ + if (symbol_prefix == NULL) + symbol_prefix = "yy"; + else + { + ++outline; + fprintf(code_file, "#define yyparse %sparse\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylex %slex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyerror %serror\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yychar %schar\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyval %sval\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylval %slval\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydebug %sdebug\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yynerrs %snerrs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyerrflag %serrflag\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyss %sss\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyssp %sssp\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyvs %svs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyvsp %svsp\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylhs %slhs\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yylen %slen\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydefred %sdefred\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yydgoto %sdgoto\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yysindex %ssindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyrindex %srindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yygindex %sgindex\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yytable %stable\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yycheck %scheck\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyname %sname\n", symbol_prefix); + ++outline; + fprintf(code_file, "#define yyrule %srule\n", symbol_prefix); + } + ++outline; + fprintf(code_file, "#define YYPREFIX \"%s\"\n", symbol_prefix); +} + + +output_rule_data() +{ + register int i; + register int j; + + + fprintf(output_file, "short %slhs[] = {%42d,", symbol_prefix, + symbol_value[start_symbol]); + + j = 10; + for (i = 3; i < nrules; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", symbol_value[rlhs[i]]); + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + + fprintf(output_file, "short %slen[] = {%42d,", symbol_prefix, 2); + + j = 10; + for (i = 3; i < nrules; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + j++; + + fprintf(output_file, "%5d,", rrhs[i + 1] - rrhs[i] - 1); + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); +} + + +output_yydefred() +{ + register int i, j; + + fprintf(output_file, "short %sdefred[] = {%39d,", symbol_prefix, + (defred[0] ? defred[0] - 2 : 0)); + + j = 10; + for (i = 1; i < nstates; i++) + { + if (j < 10) + ++j; + else + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + + fprintf(output_file, "%5d,", (defred[i] ? defred[i] - 2 : 0)); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); +} + + +output_actions() +{ + nvectors = 2*nstates + nvars; + + froms = NEW2(nvectors, short *); + tos = NEW2(nvectors, short *); + tally = NEW2(nvectors, short); + width = NEW2(nvectors, short); + + token_actions(); + FREE(lookaheads); + FREE(LA); + FREE(LAruleno); + FREE(accessing_symbol); + + goto_actions(); + FREE(goto_map + ntokens); + FREE(from_state); + FREE(to_state); + + sort_actions(); + pack_table(); + output_base(); + output_table(); + output_check(); +} + + +token_actions() +{ + register int i, j; + register int shiftcount, reducecount; + register int max, min; + register short *actionrow, *r, *s; + register action *p; + + actionrow = NEW2(2*ntokens, short); + for (i = 0; i < nstates; ++i) + { + if (parser[i]) + { + for (j = 0; j < 2*ntokens; ++j) + actionrow[j] = 0; + + shiftcount = 0; + reducecount = 0; + for (p = parser[i]; p; p = p->next) + { + if (p->suppressed == 0) + { + if (p->action_code == SHIFT) + { + ++shiftcount; + actionrow[p->symbol] = p->number; + } + else if (p->action_code == REDUCE && p->number != defred[i]) + { + ++reducecount; + actionrow[p->symbol + ntokens] = p->number; + } + } + } + + tally[i] = shiftcount; + tally[nstates+i] = reducecount; + width[i] = 0; + width[nstates+i] = 0; + if (shiftcount > 0) + { + froms[i] = r = NEW2(shiftcount, short); + tos[i] = s = NEW2(shiftcount, short); + min = MAXSHORT; + max = 0; + for (j = 0; j < ntokens; ++j) + { + if (actionrow[j]) + { + if (min > symbol_value[j]) + min = symbol_value[j]; + if (max < symbol_value[j]) + max = symbol_value[j]; + *r++ = symbol_value[j]; + *s++ = actionrow[j]; + } + } + width[i] = max - min + 1; + } + if (reducecount > 0) + { + froms[nstates+i] = r = NEW2(reducecount, short); + tos[nstates+i] = s = NEW2(reducecount, short); + min = MAXSHORT; + max = 0; + for (j = 0; j < ntokens; ++j) + { + if (actionrow[ntokens+j]) + { + if (min > symbol_value[j]) + min = symbol_value[j]; + if (max < symbol_value[j]) + max = symbol_value[j]; + *r++ = symbol_value[j]; + *s++ = actionrow[ntokens+j] - 2; + } + } + width[nstates+i] = max - min + 1; + } + } + } + FREE(actionrow); +} + +goto_actions() +{ + register int i, j, k; + + state_count = NEW2(nstates, short); + + k = default_goto(start_symbol + 1); + fprintf(output_file, "short %sdgoto[] = {%40d,", symbol_prefix, k); + save_column(start_symbol + 1, k); + + j = 10; + for (i = start_symbol + 2; i < nsyms; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + k = default_goto(i); + fprintf(output_file, "%5d,", k); + save_column(i, k); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(state_count); +} + +int +default_goto(symbol) +int symbol; +{ + register int i; + register int m; + register int n; + register int default_state; + register int max; + + m = goto_map[symbol]; + n = goto_map[symbol + 1]; + + if (m == n) return (0); + + for (i = 0; i < nstates; i++) + state_count[i] = 0; + + for (i = m; i < n; i++) + state_count[to_state[i]]++; + + max = 0; + default_state = 0; + for (i = 0; i < nstates; i++) + { + if (state_count[i] > max) + { + max = state_count[i]; + default_state = i; + } + } + + return (default_state); +} + + + +save_column(symbol, default_state) +int symbol; +int default_state; +{ + register int i; + register int m; + register int n; + register short *sp; + register short *sp1; + register short *sp2; + register int count; + register int symno; + + m = goto_map[symbol]; + n = goto_map[symbol + 1]; + + count = 0; + for (i = m; i < n; i++) + { + if (to_state[i] != default_state) + ++count; + } + if (count == 0) return; + + symno = symbol_value[symbol] + 2*nstates; + + froms[symno] = sp1 = sp = NEW2(count, short); + tos[symno] = sp2 = NEW2(count, short); + + for (i = m; i < n; i++) + { + if (to_state[i] != default_state) + { + *sp1++ = from_state[i]; + *sp2++ = to_state[i]; + } + } + + tally[symno] = count; + width[symno] = sp1[-1] - sp[0] + 1; +} + +sort_actions() +{ + register int i; + register int j; + register int k; + register int t; + register int w; + + order = NEW2(nvectors, short); + nentries = 0; + + for (i = 0; i < nvectors; i++) + { + if (tally[i] > 0) + { + t = tally[i]; + w = width[i]; + j = nentries - 1; + + while (j >= 0 && (width[order[j]] < w)) + j--; + + while (j >= 0 && (width[order[j]] == w) && (tally[order[j]] < t)) + j--; + + for (k = nentries - 1; k > j; k--) + order[k + 1] = order[k]; + + order[j + 1] = i; + nentries++; + } + } +} + + +pack_table() +{ + register int i; + register int place; + register int state; + + base = NEW2(nvectors, short); + pos = NEW2(nentries, short); + + maxtable = 1000; + table = NEW2(maxtable, short); + check = NEW2(maxtable, short); + + lowzero = 0; + high = 0; + + for (i = 0; i < maxtable; i++) + check[i] = -1; + + for (i = 0; i < nentries; i++) + { + state = matching_vector(i); + + if (state < 0) + place = pack_vector(i); + else + place = base[state]; + + pos[i] = place; + base[order[i]] = place; + } + + for (i = 0; i < nvectors; i++) + { + if (froms[i]) + FREE(froms[i]); + if (tos[i]) + FREE(tos[i]); + } + + FREE(froms); + FREE(tos); + FREE(pos); +} + + +/* The function matching_vector determines if the vector specified by */ +/* the input parameter matches a previously considered vector. The */ +/* test at the start of the function checks if the vector represents */ +/* a row of shifts over terminal symbols or a row of reductions, or a */ +/* column of shifts over a nonterminal symbol. Berkeley Yacc does not */ +/* check if a column of shifts over a nonterminal symbols matches a */ +/* previously considered vector. Because of the nature of LR parsing */ +/* tables, no two columns can match. Therefore, the only possible */ +/* match would be between a row and a column. Such matches are */ +/* unlikely. Therefore, to save time, no attempt is made to see if a */ +/* column matches a previously considered vector. */ +/* */ +/* Matching_vector is poorly designed. The test could easily be made */ +/* faster. Also, it depends on the vectors being in a specific */ +/* order. */ + +int +matching_vector(vector) +int vector; +{ + register int i; + register int j; + register int k; + register int t; + register int w; + register int match; + register int prev; + + i = order[vector]; + if (i >= 2*nstates) + return (-1); + + t = tally[i]; + w = width[i]; + + for (prev = vector - 1; prev >= 0; prev--) + { + j = order[prev]; + if (width[j] != w || tally[j] != t) + return (-1); + + match = 1; + for (k = 0; match && k < t; k++) + { + if (tos[j][k] != tos[i][k] || froms[j][k] != froms[i][k]) + match = 0; + } + + if (match) + return (j); + } + + return (-1); +} + + + +int +pack_vector(vector) +int vector; +{ + register int i, j, k, l; + register int t; + register int loc; + register int ok; + register short *from; + register short *to; + int newmax; + + i = order[vector]; + t = tally[i]; + assert(t); + + from = froms[i]; + to = tos[i]; + + j = lowzero - from[0]; + for (k = 1; k < t; ++k) + if (lowzero - from[k] > j) + j = lowzero - from[k]; + for (;; ++j) + { + if (j == 0) + continue; + ok = 1; + for (k = 0; ok && k < t; k++) + { + loc = j + from[k]; + if (loc >= maxtable) + { + if (loc >= MAXTABLE) + fatal("maximum table size exceeded"); + + newmax = maxtable; + do { newmax += 200; } while (newmax <= loc); + table = (short *) REALLOC(table, newmax*sizeof(short)); + if (table == 0) no_space(); + check = (short *) REALLOC(check, newmax*sizeof(short)); + if (check == 0) no_space(); + for (l = maxtable; l < newmax; ++l) + { + table[l] = 0; + check[l] = -1; + } + maxtable = newmax; + } + + if (check[loc] != -1) + ok = 0; + } + for (k = 0; ok && k < vector; k++) + { + if (pos[k] == j) + ok = 0; + } + if (ok) + { + for (k = 0; k < t; k++) + { + loc = j + from[k]; + table[loc] = to[k]; + check[loc] = from[k]; + if (loc > high) high = loc; + } + + while (check[lowzero] != -1) + ++lowzero; + + return (j); + } + } +} + + + +output_base() +{ + register int i, j; + + fprintf(output_file, "short %ssindex[] = {%39d,", symbol_prefix, base[0]); + + j = 10; + for (i = 1; i < nstates; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\nshort %srindex[] = {%39d,", symbol_prefix, + base[nstates]); + + j = 10; + for (i = nstates + 1; i < 2*nstates; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\nshort %sgindex[] = {%39d,", symbol_prefix, + base[2*nstates]); + + j = 10; + for (i = 2*nstates + 1; i < nvectors - 1; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", base[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(base); +} + + + +output_table() +{ + register int i; + register int j; + + ++outline; + fprintf(code_file, "#define YYTABLESIZE %d\n", high); + fprintf(output_file, "short %stable[] = {%40d,", symbol_prefix, + table[0]); + + j = 10; + for (i = 1; i <= high; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", table[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(table); +} + + + +output_check() +{ + register int i; + register int j; + + fprintf(output_file, "short %scheck[] = {%40d,", symbol_prefix, + check[0]); + + j = 10; + for (i = 1; i <= high; i++) + { + if (j >= 10) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 1; + } + else + ++j; + + fprintf(output_file, "%5d,", check[i]); + } + + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(check); +} + + +int +is_C_identifier(name) +char *name; +{ + register char *s; + register int c; + + s = name; + c = *s; + if (c == '"') + { + c = *++s; + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while ((c = *++s) != '"') + { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); + } + + if (!isalpha(c) && c != '_' && c != '$') + return (0); + while (c = *++s) + { + if (!isalnum(c) && c != '_' && c != '$') + return (0); + } + return (1); +} + + +output_defines() +{ + register int c, i; + register char *s; + + for (i = 2; i < ntokens; ++i) + { + s = symbol_name[i]; + if (is_C_identifier(s)) + { + fprintf(code_file, "#define "); + if (dflag) fprintf(defines_file, "#define "); + c = *s; + if (c == '"') + { + while ((c = *++s) != '"') + { + putc(c, code_file); + if (dflag) putc(c, defines_file); + } + } + else + { + do + { + putc(c, code_file); + if (dflag) putc(c, defines_file); + } + while (c = *++s); + } + ++outline; + fprintf(code_file, " %d\n", symbol_value[i]); + if (dflag) fprintf(defines_file, " %d\n", symbol_value[i]); + } + } + + ++outline; + fprintf(code_file, "#define YYERRCODE %d\n", symbol_value[1]); + + if (dflag && unionized) + { + fclose(union_file); + union_file = fopen(union_file_name, "r"); + if (union_file == NULL) open_error(union_file_name); + while ((c = getc(union_file)) != EOF) + putc(c, defines_file); + fprintf(defines_file, " YYSTYPE;\nextern YYSTYPE %slval;\n", + symbol_prefix); + } +} + + +output_stored_text() +{ + register int c; + register FILE *in, *out; + + fclose(text_file); + text_file = fopen(text_file_name, "r"); + if (text_file == NULL) + open_error(text_file_name); + in = text_file; + if ((c = getc(in)) == EOF) + return; + out = code_file; + if (c == '\n') + ++outline; + putc(c, out); + while ((c = getc(in)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + } + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +output_debug() +{ + register int i, j, k, max; + char **symnam, *s; + + ++outline; + fprintf(code_file, "#define YYFINAL %d\n", final_state); + outline += 3; + fprintf(code_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n", + tflag); + if (rflag) + fprintf(output_file, "#ifndef YYDEBUG\n#define YYDEBUG %d\n#endif\n", + tflag); + + max = 0; + for (i = 2; i < ntokens; ++i) + if (symbol_value[i] > max) + max = symbol_value[i]; + ++outline; + fprintf(code_file, "#define YYMAXTOKEN %d\n", max); + + symnam = (char **) MALLOC((max+1)*sizeof(char *)); + if (symnam == 0) no_space(); + + /* Note that it is not necessary to initialize the element */ + /* symnam[max]. */ + for (i = 0; i < max; ++i) + symnam[i] = 0; + for (i = ntokens - 1; i >= 2; --i) + symnam[symbol_value[i]] = symbol_name[i]; + symnam[0] = "end-of-file"; + + if (!rflag) ++outline; + fprintf(output_file, "#if YYDEBUG\nchar *%sname[] = {", symbol_prefix); + j = 80; + for (i = 0; i <= max; ++i) + { + if (s = symnam[i]) + { + if (s[0] == '"') + { + k = 7; + while (*++s != '"') + { + ++k; + if (*s == '\\') + { + k += 2; + if (*++s == '\\') + ++k; + } + } + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + fprintf(output_file, "\"\\\""); + s = symnam[i]; + while (*++s != '"') + { + if (*s == '\\') + { + fprintf(output_file, "\\\\"); + if (*++s == '\\') + fprintf(output_file, "\\\\"); + else + putc(*s, output_file); + } + else + putc(*s, output_file); + } + fprintf(output_file, "\\\"\","); + } + else if (s[0] == '\'') + { + if (s[1] == '"') + { + j += 7; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 7; + } + fprintf(output_file, "\"'\\\"'\","); + } + else + { + k = 5; + while (*++s != '\'') + { + ++k; + if (*s == '\\') + { + k += 2; + if (*++s == '\\') + ++k; + } + } + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + fprintf(output_file, "\"'"); + s = symnam[i]; + while (*++s != '\'') + { + if (*s == '\\') + { + fprintf(output_file, "\\\\"); + if (*++s == '\\') + fprintf(output_file, "\\\\"); + else + putc(*s, output_file); + } + else + putc(*s, output_file); + } + fprintf(output_file, "'\","); + } + } + else + { + k = strlen(s) + 3; + j += k; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = k; + } + putc('"', output_file); + do { putc(*s, output_file); } while (*++s); + fprintf(output_file, "\","); + } + } + else + { + j += 2; + if (j > 80) + { + if (!rflag) ++outline; + putc('\n', output_file); + j = 2; + } + fprintf(output_file, "0,"); + } + } + if (!rflag) outline += 2; + fprintf(output_file, "\n};\n"); + FREE(symnam); + + if (!rflag) ++outline; + fprintf(output_file, "char *%srule[] = {\n", symbol_prefix); + for (i = 2; i < nrules; ++i) + { + fprintf(output_file, "\"%s :", symbol_name[rlhs[i]]); + for (j = rrhs[i]; ritem[j] > 0; ++j) + { + s = symbol_name[ritem[j]]; + if (s[0] == '"') + { + fprintf(output_file, " \\\""); + while (*++s != '"') + { + if (*s == '\\') + { + if (s[1] == '\\') + fprintf(output_file, "\\\\\\\\"); + else + fprintf(output_file, "\\\\%c", s[1]); + ++s; + } + else + putc(*s, output_file); + } + fprintf(output_file, "\\\""); + } + else if (s[0] == '\'') + { + if (s[1] == '"') + fprintf(output_file, " '\\\"'"); + else if (s[1] == '\\') + { + if (s[2] == '\\') + fprintf(output_file, " '\\\\\\\\"); + else + fprintf(output_file, " '\\\\%c", s[2]); + s += 2; + while (*++s != '\'') + putc(*s, output_file); + putc('\'', output_file); + } + else + fprintf(output_file, " '%c'", s[1]); + } + else + fprintf(output_file, " %s", s); + } + if (!rflag) ++outline; + fprintf(output_file, "\",\n"); + } + + if (!rflag) outline += 2; + fprintf(output_file, "};\n#endif\n"); +} + + +output_stype() +{ + if (!unionized && ntags == 0) + { + outline += 3; + fprintf(code_file, "#ifndef YYSTYPE\ntypedef int YYSTYPE;\n#endif\n"); + } +} + + +output_trailing_text() +{ + register int c, last; + register FILE *in, *out; + + if (line == 0) + return; + + in = input_file; + out = code_file; + c = *cptr; + if (c == '\n') + { + ++lineno; + if ((c = getc(in)) == EOF) + return; + if (!lflag) + { + ++outline; + fprintf(out, line_format, lineno, input_file_name); + } + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + else + { + if (!lflag) + { + ++outline; + fprintf(out, line_format, lineno, input_file_name); + } + do { putc(c, out); } while ((c = *++cptr) != '\n'); + ++outline; + putc('\n', out); + last = '\n'; + } + + while ((c = getc(in)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + + if (last != '\n') + { + ++outline; + putc('\n', out); + } + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +output_semantic_actions() +{ + register int c, last; + register FILE *out; + + fclose(action_file); + action_file = fopen(action_file_name, "r"); + if (action_file == NULL) + open_error(action_file_name); + + if ((c = getc(action_file)) == EOF) + return; + + out = code_file; + last = c; + if (c == '\n') + ++outline; + putc(c, out); + while ((c = getc(action_file)) != EOF) + { + if (c == '\n') + ++outline; + putc(c, out); + last = c; + } + + if (last != '\n') + { + ++outline; + putc('\n', out); + } + + if (!lflag) + fprintf(out, line_format, ++outline + 1, code_file_name); +} + + +free_itemsets() +{ + register core *cp, *next; + + FREE(state_table); + for (cp = first_state; cp; cp = next) + { + next = cp->next; + FREE(cp); + } +} + + +free_shifts() +{ + register shifts *sp, *next; + + FREE(shift_table); + for (sp = first_shift; sp; sp = next) + { + next = sp->next; + FREE(sp); + } +} + + + +free_reductions() +{ + register reductions *rp, *next; + + FREE(reduction_table); + for (rp = first_reduction; rp; rp = next) + { + next = rp->next; + FREE(rp); + } +} diff --git a/usr.bin/yacc/reader.c b/usr.bin/yacc/reader.c new file mode 100644 index 0000000..3b724d3 --- /dev/null +++ b/usr.bin/yacc/reader.c @@ -0,0 +1,1810 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)reader.c 5.7 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +/* The line size must be a positive integer. One hundred was chosen */ +/* because few lines in Yacc input grammars exceed 100 characters. */ +/* Note that if a line exceeds LINESIZE characters, the line buffer */ +/* will be expanded to accomodate it. */ + +#define LINESIZE 100 + +char *cache; +int cinc, cache_size; + +int ntags, tagmax; +char **tag_table; + +char saw_eof, unionized; +char *cptr, *line; +int linesize; + +bucket *goal; +int prec; +int gensym; +char last_was_action; + +int maxitems; +bucket **pitem; + +int maxrules; +bucket **plhs; + +int name_pool_size; +char *name_pool; + +char line_format[] = "#line %d \"%s\"\n"; + + +cachec(c) +int c; +{ + assert(cinc >= 0); + if (cinc >= cache_size) + { + cache_size += 256; + cache = REALLOC(cache, cache_size); + if (cache == 0) no_space(); + } + cache[cinc] = c; + ++cinc; +} + + +get_line() +{ + register FILE *f = input_file; + register int c; + register int i; + + if (saw_eof || (c = getc(f)) == EOF) + { + if (line) { FREE(line); line = 0; } + cptr = 0; + saw_eof = 1; + return; + } + + if (line == 0 || linesize != (LINESIZE + 1)) + { + if (line) FREE(line); + linesize = LINESIZE + 1; + line = MALLOC(linesize); + if (line == 0) no_space(); + } + + i = 0; + ++lineno; + for (;;) + { + line[i] = c; + if (c == '\n') { cptr = line; return; } + if (++i >= linesize) + { + linesize += LINESIZE; + line = REALLOC(line, linesize); + if (line == 0) no_space(); + } + c = getc(f); + if (c == EOF) + { + line[i] = '\n'; + saw_eof = 1; + cptr = line; + return; + } + } +} + + +char * +dup_line() +{ + register char *p, *s, *t; + + if (line == 0) return (0); + s = line; + while (*s != '\n') ++s; + p = MALLOC(s - line + 1); + if (p == 0) no_space(); + + s = line; + t = p; + while ((*t++ = *s++) != '\n') continue; + return (p); +} + + +skip_comment() +{ + register char *s; + + int st_lineno = lineno; + char *st_line = dup_line(); + char *st_cptr = st_line + (cptr - line); + + s = cptr + 2; + for (;;) + { + if (*s == '*' && s[1] == '/') + { + cptr = s + 2; + FREE(st_line); + return; + } + if (*s == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(st_lineno, st_line, st_cptr); + s = cptr; + } + else + ++s; + } +} + + +int +nextc() +{ + register char *s; + + if (line == 0) + { + get_line(); + if (line == 0) + return (EOF); + } + + s = cptr; + for (;;) + { + switch (*s) + { + case '\n': + get_line(); + if (line == 0) return (EOF); + s = cptr; + break; + + case ' ': + case '\t': + case '\f': + case '\r': + case '\v': + case ',': + case ';': + ++s; + break; + + case '\\': + cptr = s; + return ('%'); + + case '/': + if (s[1] == '*') + { + cptr = s; + skip_comment(); + s = cptr; + break; + } + else if (s[1] == '/') + { + get_line(); + if (line == 0) return (EOF); + s = cptr; + break; + } + /* fall through */ + + default: + cptr = s; + return (*s); + } + } +} + + +int +keyword() +{ + register int c; + char *t_cptr = cptr; + + c = *++cptr; + if (isalpha(c)) + { + cinc = 0; + for (;;) + { + if (isalpha(c)) + { + if (isupper(c)) c = tolower(c); + cachec(c); + } + else if (isdigit(c) || c == '_' || c == '.' || c == '$') + cachec(c); + else + break; + c = *++cptr; + } + cachec(NUL); + + if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0) + return (TOKEN); + if (strcmp(cache, "type") == 0) + return (TYPE); + if (strcmp(cache, "left") == 0) + return (LEFT); + if (strcmp(cache, "right") == 0) + return (RIGHT); + if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0) + return (NONASSOC); + if (strcmp(cache, "start") == 0) + return (START); + if (strcmp(cache, "union") == 0) + return (UNION); + if (strcmp(cache, "ident") == 0) + return (IDENT); + } + else + { + ++cptr; + if (c == '{') + return (TEXT); + if (c == '%' || c == '\\') + return (MARK); + if (c == '<') + return (LEFT); + if (c == '>') + return (RIGHT); + if (c == '0') + return (TOKEN); + if (c == '2') + return (NONASSOC); + } + syntax_error(lineno, line, t_cptr); + /*NOTREACHED*/ +} + + +copy_ident() +{ + register int c; + register FILE *f = output_file; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '"') syntax_error(lineno, line, cptr); + ++outline; + fprintf(f, "#ident \""); + for (;;) + { + c = *++cptr; + if (c == '\n') + { + fprintf(f, "\"\n"); + return; + } + putc(c, f); + if (c == '"') + { + putc('\n', f); + ++cptr; + return; + } + } +} + + +copy_text() +{ + register int c; + int quote; + register FILE *f = text_file; + int need_newline = 0; + int t_lineno = lineno; + char *t_line = dup_line(); + char *t_cptr = t_line + (cptr - line - 2); + + if (*cptr == '\n') + { + get_line(); + if (line == 0) + unterminated_text(t_lineno, t_line, t_cptr); + } + if (!lflag) fprintf(f, line_format, lineno, input_file_name); + +loop: + c = *cptr++; + switch (c) + { + case '\n': + next_line: + putc('\n', f); + need_newline = 0; + get_line(); + if (line) goto loop; + unterminated_text(t_lineno, t_line, t_cptr); + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + putc(c, f); + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == quote) + { + need_newline = 1; + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, f); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + putc(c, f); + need_newline = 1; + c = *cptr; + if (c == '/') + { + putc('*', f); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + fprintf(f, "* "); + else + putc(c, f); + } + fprintf(f, "*/"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', f); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') + { + putc('/', f); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + need_newline = 1; + goto loop; + + case '%': + case '\\': + if (*cptr == '}') + { + if (need_newline) putc('\n', f); + ++cptr; + FREE(t_line); + return; + } + /* fall through */ + + default: + putc(c, f); + need_newline = 1; + goto loop; + } +} + + +copy_union() +{ + register int c; + int quote; + int depth; + int u_lineno = lineno; + char *u_line = dup_line(); + char *u_cptr = u_line + (cptr - line - 6); + + if (unionized) over_unionized(cptr - 6); + unionized = 1; + + if (!lflag) + fprintf(text_file, line_format, lineno, input_file_name); + + fprintf(text_file, "typedef union"); + if (dflag) fprintf(union_file, "typedef union"); + + depth = 0; +loop: + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + switch (c) + { + case '\n': + next_line: + get_line(); + if (line == 0) unterminated_union(u_lineno, u_line, u_cptr); + goto loop; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth == 0) + { + fprintf(text_file, " YYSTYPE;\n"); + FREE(u_line); + return; + } + goto loop; + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + for (;;) + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == quote) + { + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + c = *cptr; + if (c == '/') + { + putc('*', text_file); + if (dflag) putc('*', union_file); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + { + fprintf(text_file, "* "); + if (dflag) fprintf(union_file, "* "); + } + else + { + putc(c, text_file); + if (dflag) putc(c, union_file); + } + } + fprintf(text_file, "*/\n"); + if (dflag) fprintf(union_file, "*/\n"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', text_file); + if (dflag) putc('*', union_file); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, text_file); + if (dflag) putc(c, union_file); + if (c == '*' && *cptr == '/') + { + putc('/', text_file); + if (dflag) putc('/', union_file); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +int +hexval(c) +int c; +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (-1); +} + + +bucket * +get_literal() +{ + register int c, quote; + register int i; + register int n; + register char *s; + register bucket *bp; + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line); + + quote = *cptr++; + cinc = 0; + for (;;) + { + c = *cptr++; + if (c == quote) break; + if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + char *c_cptr = cptr - 1; + + c = *cptr++; + switch (c) + { + case '\n': + get_line(); + if (line == 0) unterminated_string(s_lineno, s_line, s_cptr); + continue; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + n = c - '0'; + c = *cptr; + if (IS_OCTAL(c)) + { + n = (n << 3) + (c - '0'); + c = *++cptr; + if (IS_OCTAL(c)) + { + n = (n << 3) + (c - '0'); + ++cptr; + } + } + if (n > MAXCHAR) illegal_character(c_cptr); + c = n; + break; + + case 'x': + c = *cptr++; + n = hexval(c); + if (n < 0 || n >= 16) + illegal_character(c_cptr); + for (;;) + { + c = *cptr; + i = hexval(c); + if (i < 0 || i >= 16) break; + ++cptr; + n = (n << 4) + i; + if (n > MAXCHAR) illegal_character(c_cptr); + } + c = n; + break; + + case 'a': c = 7; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + } + } + cachec(c); + } + FREE(s_line); + + n = cinc; + s = MALLOC(n); + if (s == 0) no_space(); + + for (i = 0; i < n; ++i) + s[i] = cache[i]; + + cinc = 0; + if (n == 1) + cachec('\''); + else + cachec('"'); + + for (i = 0; i < n; ++i) + { + c = ((unsigned char *)s)[i]; + if (c == '\\' || c == cache[0]) + { + cachec('\\'); + cachec(c); + } + else if (isprint(c)) + cachec(c); + else + { + cachec('\\'); + switch (c) + { + case 7: cachec('a'); break; + case '\b': cachec('b'); break; + case '\f': cachec('f'); break; + case '\n': cachec('n'); break; + case '\r': cachec('r'); break; + case '\t': cachec('t'); break; + case '\v': cachec('v'); break; + default: + cachec(((c >> 6) & 7) + '0'); + cachec(((c >> 3) & 7) + '0'); + cachec((c & 7) + '0'); + break; + } + } + } + + if (n == 1) + cachec('\''); + else + cachec('"'); + + cachec(NUL); + bp = lookup(cache); + bp->class = TERM; + if (n == 1 && bp->value == UNDEFINED) + bp->value = *(unsigned char *)s; + FREE(s); + + return (bp); +} + + +int +is_reserved(name) +char *name; +{ + char *s; + + if (strcmp(name, ".") == 0 || + strcmp(name, "$accept") == 0 || + strcmp(name, "$end") == 0) + return (1); + + if (name[0] == '$' && name[1] == '$' && isdigit(name[2])) + { + s = name + 3; + while (isdigit(*s)) ++s; + if (*s == NUL) return (1); + } + + return (0); +} + + +bucket * +get_name() +{ + register int c; + + cinc = 0; + for (c = *cptr; IS_IDENT(c); c = *++cptr) + cachec(c); + cachec(NUL); + + if (is_reserved(cache)) used_reserved(cache); + + return (lookup(cache)); +} + + +int +get_number() +{ + register int c; + register int n; + + n = 0; + for (c = *cptr; isdigit(c); c = *++cptr) + n = 10*n + (c - '0'); + + return (n); +} + + +char * +get_tag() +{ + register int c; + register int i; + register char *s; + int t_lineno = lineno; + char *t_line = dup_line(); + char *t_cptr = t_line + (cptr - line); + + ++cptr; + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (!isalpha(c) && c != '_' && c != '$') + illegal_tag(t_lineno, t_line, t_cptr); + + cinc = 0; + do { cachec(c); c = *++cptr; } while (IS_IDENT(c)); + cachec(NUL); + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '>') + illegal_tag(t_lineno, t_line, t_cptr); + ++cptr; + + for (i = 0; i < ntags; ++i) + { + if (strcmp(cache, tag_table[i]) == 0) + return (tag_table[i]); + } + + if (ntags >= tagmax) + { + tagmax += 16; + tag_table = (char **) + (tag_table ? REALLOC(tag_table, tagmax*sizeof(char *)) + : MALLOC(tagmax*sizeof(char *))); + if (tag_table == 0) no_space(); + } + + s = MALLOC(cinc); + if (s == 0) no_space(); + strcpy(s, cache); + tag_table[ntags] = s; + ++ntags; + FREE(t_line); + return (s); +} + + +declare_tokens(assoc) +int assoc; +{ + register int c; + register bucket *bp; + int value; + char *tag = 0; + + if (assoc != TOKEN) ++prec; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c == '<') + { + tag = get_tag(); + c = nextc(); + if (c == EOF) unexpected_EOF(); + } + + for (;;) + { + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + return; + + if (bp == goal) tokenized_start(bp->name); + bp->class = TERM; + + if (tag) + { + if (bp->tag && tag != bp->tag) + retyped_warning(bp->name); + bp->tag = tag; + } + + if (assoc != TOKEN) + { + if (bp->prec && prec != bp->prec) + reprec_warning(bp->name); + bp->assoc = assoc; + bp->prec = prec; + } + + c = nextc(); + if (c == EOF) unexpected_EOF(); + value = UNDEFINED; + if (isdigit(c)) + { + value = get_number(); + if (bp->value != UNDEFINED && value != bp->value) + revalued_warning(bp->name); + bp->value = value; + c = nextc(); + if (c == EOF) unexpected_EOF(); + } + } +} + + +declare_types() +{ + register int c; + register bucket *bp; + char *tag; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '<') syntax_error(lineno, line, cptr); + tag = get_tag(); + + for (;;) + { + c = nextc(); + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + return; + + if (bp->tag && tag != bp->tag) + retyped_warning(bp->name); + bp->tag = tag; + } +} + + +declare_start() +{ + register int c; + register bucket *bp; + + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (!isalpha(c) && c != '_' && c != '.' && c != '$') + syntax_error(lineno, line, cptr); + bp = get_name(); + if (bp->class == TERM) + terminal_start(bp->name); + if (goal && goal != bp) + restarted_warning(); + goal = bp; +} + + +read_declarations() +{ + register int c, k; + + cache_size = 256; + cache = MALLOC(cache_size); + if (cache == 0) no_space(); + + for (;;) + { + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != '%') syntax_error(lineno, line, cptr); + switch (k = keyword()) + { + case MARK: + return; + + case IDENT: + copy_ident(); + break; + + case TEXT: + copy_text(); + break; + + case UNION: + copy_union(); + break; + + case TOKEN: + case LEFT: + case RIGHT: + case NONASSOC: + declare_tokens(k); + break; + + case TYPE: + declare_types(); + break; + + case START: + declare_start(); + break; + } + } +} + + +initialize_grammar() +{ + nitems = 4; + maxitems = 300; + pitem = (bucket **) MALLOC(maxitems*sizeof(bucket *)); + if (pitem == 0) no_space(); + pitem[0] = 0; + pitem[1] = 0; + pitem[2] = 0; + pitem[3] = 0; + + nrules = 3; + maxrules = 100; + plhs = (bucket **) MALLOC(maxrules*sizeof(bucket *)); + if (plhs == 0) no_space(); + plhs[0] = 0; + plhs[1] = 0; + plhs[2] = 0; + rprec = (short *) MALLOC(maxrules*sizeof(short)); + if (rprec == 0) no_space(); + rprec[0] = 0; + rprec[1] = 0; + rprec[2] = 0; + rassoc = (char *) MALLOC(maxrules*sizeof(char)); + if (rassoc == 0) no_space(); + rassoc[0] = TOKEN; + rassoc[1] = TOKEN; + rassoc[2] = TOKEN; +} + + +expand_items() +{ + maxitems += 300; + pitem = (bucket **) REALLOC(pitem, maxitems*sizeof(bucket *)); + if (pitem == 0) no_space(); +} + + +expand_rules() +{ + maxrules += 100; + plhs = (bucket **) REALLOC(plhs, maxrules*sizeof(bucket *)); + if (plhs == 0) no_space(); + rprec = (short *) REALLOC(rprec, maxrules*sizeof(short)); + if (rprec == 0) no_space(); + rassoc = (char *) REALLOC(rassoc, maxrules*sizeof(char)); + if (rassoc == 0) no_space(); +} + + +advance_to_start() +{ + register int c; + register bucket *bp; + char *s_cptr; + int s_lineno; + + for (;;) + { + c = nextc(); + if (c != '%') break; + s_cptr = cptr; + switch (keyword()) + { + case MARK: + no_grammar(); + + case TEXT: + copy_text(); + break; + + case START: + declare_start(); + break; + + default: + syntax_error(lineno, line, s_cptr); + } + } + + c = nextc(); + if (!isalpha(c) && c != '_' && c != '.' && c != '_') + syntax_error(lineno, line, cptr); + bp = get_name(); + if (goal == 0) + { + if (bp->class == TERM) + terminal_start(bp->name); + goal = bp; + } + + s_lineno = lineno; + c = nextc(); + if (c == EOF) unexpected_EOF(); + if (c != ':') syntax_error(lineno, line, cptr); + start_rule(bp, s_lineno); + ++cptr; +} + + +start_rule(bp, s_lineno) +register bucket *bp; +int s_lineno; +{ + if (bp->class == TERM) + terminal_lhs(s_lineno); + bp->class = NONTERM; + if (nrules >= maxrules) + expand_rules(); + plhs[nrules] = bp; + rprec[nrules] = UNDEFINED; + rassoc[nrules] = TOKEN; +} + + +end_rule() +{ + register int i; + + if (!last_was_action && plhs[nrules]->tag) + { + for (i = nitems - 1; pitem[i]; --i) continue; + if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag) + default_action_warning(); + } + + last_was_action = 0; + if (nitems >= maxitems) expand_items(); + pitem[nitems] = 0; + ++nitems; + ++nrules; +} + + +insert_empty_rule() +{ + register bucket *bp, **bpp; + + assert(cache); + sprintf(cache, "$$%d", ++gensym); + bp = make_bucket(cache); + last_symbol->next = bp; + last_symbol = bp; + bp->tag = plhs[nrules]->tag; + bp->class = NONTERM; + + if ((nitems += 2) > maxitems) + expand_items(); + bpp = pitem + nitems - 1; + *bpp-- = bp; + while (bpp[0] = bpp[-1]) --bpp; + + if (++nrules >= maxrules) + expand_rules(); + plhs[nrules] = plhs[nrules-1]; + plhs[nrules-1] = bp; + rprec[nrules] = rprec[nrules-1]; + rprec[nrules-1] = 0; + rassoc[nrules] = rassoc[nrules-1]; + rassoc[nrules-1] = TOKEN; +} + + +add_symbol() +{ + register int c; + register bucket *bp; + int s_lineno = lineno; + + c = *cptr; + if (c == '\'' || c == '"') + bp = get_literal(); + else + bp = get_name(); + + c = nextc(); + if (c == ':') + { + end_rule(); + start_rule(bp, s_lineno); + ++cptr; + return; + } + + if (last_was_action) + insert_empty_rule(); + last_was_action = 0; + + if (++nitems > maxitems) + expand_items(); + pitem[nitems-1] = bp; +} + + +copy_action() +{ + register int c; + register int i, n; + int depth; + int quote; + char *tag; + register FILE *f = action_file; + int a_lineno = lineno; + char *a_line = dup_line(); + char *a_cptr = a_line + (cptr - line); + + if (last_was_action) + insert_empty_rule(); + last_was_action = 1; + + fprintf(f, "case %d:\n", nrules - 2); + if (!lflag) + fprintf(f, line_format, lineno, input_file_name); + if (*cptr == '=') ++cptr; + + n = 0; + for (i = nitems - 1; pitem[i]; --i) ++n; + + depth = 0; +loop: + c = *cptr; + if (c == '$') + { + if (cptr[1] == '<') + { + int d_lineno = lineno; + char *d_line = dup_line(); + char *d_cptr = d_line + (cptr - line); + + ++cptr; + tag = get_tag(); + c = *cptr; + if (c == '$') + { + fprintf(f, "yyval.%s", tag); + ++cptr; + FREE(d_line); + goto loop; + } + else if (isdigit(c)) + { + i = get_number(); + if (i > n) dollar_warning(d_lineno, i); + fprintf(f, "yyvsp[%d].%s", i - n, tag); + FREE(d_line); + goto loop; + } + else if (c == '-' && isdigit(cptr[1])) + { + ++cptr; + i = -get_number() - n; + fprintf(f, "yyvsp[%d].%s", i, tag); + FREE(d_line); + goto loop; + } + else + dollar_error(d_lineno, d_line, d_cptr); + } + else if (cptr[1] == '$') + { + if (ntags) + { + tag = plhs[nrules]->tag; + if (tag == 0) untyped_lhs(); + fprintf(f, "yyval.%s", tag); + } + else + fprintf(f, "yyval"); + cptr += 2; + goto loop; + } + else if (isdigit(cptr[1])) + { + ++cptr; + i = get_number(); + if (ntags) + { + if (i <= 0 || i > n) + unknown_rhs(i); + tag = pitem[nitems + i - n - 1]->tag; + if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name); + fprintf(f, "yyvsp[%d].%s", i - n, tag); + } + else + { + if (i > n) + dollar_warning(lineno, i); + fprintf(f, "yyvsp[%d]", i - n); + } + goto loop; + } + else if (cptr[1] == '-') + { + cptr += 2; + i = get_number(); + if (ntags) + unknown_rhs(-i); + fprintf(f, "yyvsp[%d]", -i - n); + goto loop; + } + } + if (isalpha(c) || c == '_' || c == '$') + { + do + { + putc(c, f); + c = *++cptr; + } while (isalnum(c) || c == '_' || c == '$'); + goto loop; + } + putc(c, f); + ++cptr; + switch (c) + { + case '\n': + next_line: + get_line(); + if (line) goto loop; + unterminated_action(a_lineno, a_line, a_cptr); + + case ';': + if (depth > 0) goto loop; + fprintf(f, "\nbreak;\n"); + return; + + case '{': + ++depth; + goto loop; + + case '}': + if (--depth > 0) goto loop; + fprintf(f, "\nbreak;\n"); + return; + + case '\'': + case '"': + { + int s_lineno = lineno; + char *s_line = dup_line(); + char *s_cptr = s_line + (cptr - line - 1); + + quote = c; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == quote) + { + FREE(s_line); + goto loop; + } + if (c == '\n') + unterminated_string(s_lineno, s_line, s_cptr); + if (c == '\\') + { + c = *cptr++; + putc(c, f); + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_string(s_lineno, s_line, s_cptr); + } + } + } + } + + case '/': + c = *cptr; + if (c == '/') + { + putc('*', f); + while ((c = *++cptr) != '\n') + { + if (c == '*' && cptr[1] == '/') + fprintf(f, "* "); + else + putc(c, f); + } + fprintf(f, "*/\n"); + goto next_line; + } + if (c == '*') + { + int c_lineno = lineno; + char *c_line = dup_line(); + char *c_cptr = c_line + (cptr - line - 1); + + putc('*', f); + ++cptr; + for (;;) + { + c = *cptr++; + putc(c, f); + if (c == '*' && *cptr == '/') + { + putc('/', f); + ++cptr; + FREE(c_line); + goto loop; + } + if (c == '\n') + { + get_line(); + if (line == 0) + unterminated_comment(c_lineno, c_line, c_cptr); + } + } + } + goto loop; + + default: + goto loop; + } +} + + +int +mark_symbol() +{ + register int c; + register bucket *bp; + + c = cptr[1]; + if (c == '%' || c == '\\') + { + cptr += 2; + return (1); + } + + if (c == '=') + cptr += 2; + else if ((c == 'p' || c == 'P') && + ((c = cptr[2]) == 'r' || c == 'R') && + ((c = cptr[3]) == 'e' || c == 'E') && + ((c = cptr[4]) == 'c' || c == 'C') && + ((c = cptr[5], !IS_IDENT(c)))) + cptr += 5; + else + syntax_error(lineno, line, cptr); + + c = nextc(); + if (isalpha(c) || c == '_' || c == '.' || c == '$') + bp = get_name(); + else if (c == '\'' || c == '"') + bp = get_literal(); + else + { + syntax_error(lineno, line, cptr); + /*NOTREACHED*/ + } + + if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules]) + prec_redeclared(); + + rprec[nrules] = bp->prec; + rassoc[nrules] = bp->assoc; + return (0); +} + + +read_grammar() +{ + register int c; + + initialize_grammar(); + advance_to_start(); + + for (;;) + { + c = nextc(); + if (c == EOF) break; + if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' || + c == '"') + add_symbol(); + else if (c == '{' || c == '=') + copy_action(); + else if (c == '|') + { + end_rule(); + start_rule(plhs[nrules-1], 0); + ++cptr; + } + else if (c == '%') + { + if (mark_symbol()) break; + } + else + syntax_error(lineno, line, cptr); + } + end_rule(); +} + + +free_tags() +{ + register int i; + + if (tag_table == 0) return; + + for (i = 0; i < ntags; ++i) + { + assert(tag_table[i]); + FREE(tag_table[i]); + } + FREE(tag_table); +} + + +pack_names() +{ + register bucket *bp; + register char *p, *s, *t; + + name_pool_size = 13; /* 13 == sizeof("$end") + sizeof("$accept") */ + for (bp = first_symbol; bp; bp = bp->next) + name_pool_size += strlen(bp->name) + 1; + name_pool = MALLOC(name_pool_size); + if (name_pool == 0) no_space(); + + strcpy(name_pool, "$accept"); + strcpy(name_pool+8, "$end"); + t = name_pool + 13; + for (bp = first_symbol; bp; bp = bp->next) + { + p = t; + s = bp->name; + while (*t++ = *s++) continue; + FREE(bp->name); + bp->name = p; + } +} + + +check_symbols() +{ + register bucket *bp; + + if (goal->class == UNKNOWN) + undefined_goal(goal->name); + + for (bp = first_symbol; bp; bp = bp->next) + { + if (bp->class == UNKNOWN) + { + undefined_symbol_warning(bp->name); + bp->class = TERM; + } + } +} + + +pack_symbols() +{ + register bucket *bp; + register bucket **v; + register int i, j, k, n; + + nsyms = 2; + ntokens = 1; + for (bp = first_symbol; bp; bp = bp->next) + { + ++nsyms; + if (bp->class == TERM) ++ntokens; + } + start_symbol = ntokens; + nvars = nsyms - ntokens; + + symbol_name = (char **) MALLOC(nsyms*sizeof(char *)); + if (symbol_name == 0) no_space(); + symbol_value = (short *) MALLOC(nsyms*sizeof(short)); + if (symbol_value == 0) no_space(); + symbol_prec = (short *) MALLOC(nsyms*sizeof(short)); + if (symbol_prec == 0) no_space(); + symbol_assoc = MALLOC(nsyms); + if (symbol_assoc == 0) no_space(); + + v = (bucket **) MALLOC(nsyms*sizeof(bucket *)); + if (v == 0) no_space(); + + v[0] = 0; + v[start_symbol] = 0; + + i = 1; + j = start_symbol + 1; + for (bp = first_symbol; bp; bp = bp->next) + { + if (bp->class == TERM) + v[i++] = bp; + else + v[j++] = bp; + } + assert(i == ntokens && j == nsyms); + + for (i = 1; i < ntokens; ++i) + v[i]->index = i; + + goal->index = start_symbol + 1; + k = start_symbol + 2; + while (++i < nsyms) + if (v[i] != goal) + { + v[i]->index = k; + ++k; + } + + goal->value = 0; + k = 1; + for (i = start_symbol + 1; i < nsyms; ++i) + { + if (v[i] != goal) + { + v[i]->value = k; + ++k; + } + } + + k = 0; + for (i = 1; i < ntokens; ++i) + { + n = v[i]->value; + if (n > 256) + { + for (j = k++; j > 0 && symbol_value[j-1] > n; --j) + symbol_value[j] = symbol_value[j-1]; + symbol_value[j] = n; + } + } + + if (v[1]->value == UNDEFINED) + v[1]->value = 256; + + j = 0; + n = 257; + for (i = 2; i < ntokens; ++i) + { + if (v[i]->value == UNDEFINED) + { + while (j < k && n == symbol_value[j]) + { + while (++j < k && n == symbol_value[j]) continue; + ++n; + } + v[i]->value = n; + ++n; + } + } + + symbol_name[0] = name_pool + 8; + symbol_value[0] = 0; + symbol_prec[0] = 0; + symbol_assoc[0] = TOKEN; + for (i = 1; i < ntokens; ++i) + { + symbol_name[i] = v[i]->name; + symbol_value[i] = v[i]->value; + symbol_prec[i] = v[i]->prec; + symbol_assoc[i] = v[i]->assoc; + } + symbol_name[start_symbol] = name_pool; + symbol_value[start_symbol] = -1; + symbol_prec[start_symbol] = 0; + symbol_assoc[start_symbol] = TOKEN; + for (++i; i < nsyms; ++i) + { + k = v[i]->index; + symbol_name[k] = v[i]->name; + symbol_value[k] = v[i]->value; + symbol_prec[k] = v[i]->prec; + symbol_assoc[k] = v[i]->assoc; + } + + FREE(v); +} + + +pack_grammar() +{ + register int i, j; + int assoc, prec; + + ritem = (short *) MALLOC(nitems*sizeof(short)); + if (ritem == 0) no_space(); + rlhs = (short *) MALLOC(nrules*sizeof(short)); + if (rlhs == 0) no_space(); + rrhs = (short *) MALLOC((nrules+1)*sizeof(short)); + if (rrhs == 0) no_space(); + rprec = (short *) REALLOC(rprec, nrules*sizeof(short)); + if (rprec == 0) no_space(); + rassoc = REALLOC(rassoc, nrules); + if (rassoc == 0) no_space(); + + ritem[0] = -1; + ritem[1] = goal->index; + ritem[2] = 0; + ritem[3] = -2; + rlhs[0] = 0; + rlhs[1] = 0; + rlhs[2] = start_symbol; + rrhs[0] = 0; + rrhs[1] = 0; + rrhs[2] = 1; + + j = 4; + for (i = 3; i < nrules; ++i) + { + rlhs[i] = plhs[i]->index; + rrhs[i] = j; + assoc = TOKEN; + prec = 0; + while (pitem[j]) + { + ritem[j] = pitem[j]->index; + if (pitem[j]->class == TERM) + { + prec = pitem[j]->prec; + assoc = pitem[j]->assoc; + } + ++j; + } + ritem[j] = -i; + ++j; + if (rprec[i] == UNDEFINED) + { + rprec[i] = prec; + rassoc[i] = assoc; + } + } + rrhs[i] = j; + + FREE(plhs); + FREE(pitem); +} + + +print_grammar() +{ + register int i, j, k; + int spacing; + register FILE *f = verbose_file; + + if (!vflag) return; + + k = 1; + for (i = 2; i < nrules; ++i) + { + if (rlhs[i] != rlhs[i-1]) + { + if (i != 2) fprintf(f, "\n"); + fprintf(f, "%4d %s :", i - 2, symbol_name[rlhs[i]]); + spacing = strlen(symbol_name[rlhs[i]]) + 1; + } + else + { + fprintf(f, "%4d ", i - 2); + j = spacing; + while (--j >= 0) putc(' ', f); + putc('|', f); + } + + while (ritem[k] >= 0) + { + fprintf(f, " %s", symbol_name[ritem[k]]); + ++k; + } + ++k; + putc('\n', f); + } +} + + +reader() +{ + write_section(banner); + create_symbol_table(); + read_declarations(); + read_grammar(); + free_symbol_table(); + free_tags(); + pack_names(); + check_symbols(); + pack_symbols(); + pack_grammar(); + free_symbols(); + print_grammar(); +} diff --git a/usr.bin/yacc/skeleton.c b/usr.bin/yacc/skeleton.c new file mode 100644 index 0000000..1e51b2e --- /dev/null +++ b/usr.bin/yacc/skeleton.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)skeleton.c 5.7 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +/* The definition of yysccsid in the banner should be replaced with */ +/* a #pragma ident directive if the target C compiler supports */ +/* #pragma ident directives. */ +/* */ +/* If the skeleton is changed, the banner should be changed so that */ +/* the altered version can be easily distinguished from the original. */ +/* */ +/* The #defines included with the banner are there because they are */ +/* useful in subsequent code. The macros #defined in the header or */ +/* the body either are not useful outside of semantic actions or */ +/* are conditional. */ + +char *banner[] = +{ + "#ifndef lint", + "static char yysccsid[] = \"@(#)yaccpar 1.9 (Berkeley) 02/21/93\";", + "#endif", + "#define YYBYACC 1", + "#define YYMAJOR 1", + "#define YYMINOR 9", + "#define yyclearin (yychar=(-1))", + "#define yyerrok (yyerrflag=0)", + "#define YYRECOVERING (yyerrflag!=0)", + 0 +}; + + +char *tables[] = +{ + "extern short yylhs[];", + "extern short yylen[];", + "extern short yydefred[];", + "extern short yydgoto[];", + "extern short yysindex[];", + "extern short yyrindex[];", + "extern short yygindex[];", + "extern short yytable[];", + "extern short yycheck[];", + "#if YYDEBUG", + "extern char *yyname[];", + "extern char *yyrule[];", + "#endif", + 0 +}; + + +char *header[] = +{ + "#ifdef YYSTACKSIZE", + "#undef YYMAXDEPTH", + "#define YYMAXDEPTH YYSTACKSIZE", + "#else", + "#ifdef YYMAXDEPTH", + "#define YYSTACKSIZE YYMAXDEPTH", + "#else", + "#define YYSTACKSIZE 500", + "#define YYMAXDEPTH 500", + "#endif", + "#endif", + "int yydebug;", + "int yynerrs;", + "int yyerrflag;", + "int yychar;", + "short *yyssp;", + "YYSTYPE *yyvsp;", + "YYSTYPE yyval;", + "YYSTYPE yylval;", + "short yyss[YYSTACKSIZE];", + "YYSTYPE yyvs[YYSTACKSIZE];", + "#define yystacksize YYSTACKSIZE", + 0 +}; + + +char *body[] = +{ + "#define YYABORT goto yyabort", + "#define YYREJECT goto yyabort", + "#define YYACCEPT goto yyaccept", + "#define YYERROR goto yyerrlab", + "int", + "yyparse()", + "{", + " register int yym, yyn, yystate;", + "#if YYDEBUG", + " register char *yys;", + " extern char *getenv();", + "", + " if (yys = getenv(\"YYDEBUG\"))", + " {", + " yyn = *yys;", + " if (yyn >= '0' && yyn <= '9')", + " yydebug = yyn - '0';", + " }", + "#endif", + "", + " yynerrs = 0;", + " yyerrflag = 0;", + " yychar = (-1);", + "", + " yyssp = yyss;", + " yyvsp = yyvs;", + " *yyssp = yystate = 0;", + "", + "yyloop:", + " if (yyn = yydefred[yystate]) goto yyreduce;", + " if (yychar < 0)", + " {", + " if ((yychar = yylex()) < 0) yychar = 0;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, reading %d (%s)\\n\",", + " YYPREFIX, yystate, yychar, yys);", + " }", + "#endif", + " }", + " if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yychar)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, shifting to state %d\\n\",", + " YYPREFIX, yystate, yytable[yyn]);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate = yytable[yyn];", + " *++yyvsp = yylval;", + " yychar = (-1);", + " if (yyerrflag > 0) --yyerrflag;", + " goto yyloop;", + " }", + " if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yychar)", + " {", + " yyn = yytable[yyn];", + " goto yyreduce;", + " }", + " if (yyerrflag) goto yyinrecovery;", + "#ifdef lint", + " goto yynewerror;", + "#endif", + "yynewerror:", + " yyerror(\"syntax error\");", + "#ifdef lint", + " goto yyerrlab;", + "#endif", + "yyerrlab:", + " ++yynerrs;", + "yyinrecovery:", + " if (yyerrflag < 3)", + " {", + " yyerrflag = 3;", + " for (;;)", + " {", + " if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, error recovery shifting\\", + " to state %d\\n\", YYPREFIX, *yyssp, yytable[yyn]);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate = yytable[yyn];", + " *++yyvsp = yylval;", + " goto yyloop;", + " }", + " else", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: error recovery discarding state %d\ +\\n\",", + " YYPREFIX, *yyssp);", + "#endif", + " if (yyssp <= yyss) goto yyabort;", + " --yyssp;", + " --yyvsp;", + " }", + " }", + " }", + " else", + " {", + " if (yychar == 0) goto yyabort;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, error recovery discards token %d\ + (%s)\\n\",", + " YYPREFIX, yystate, yychar, yys);", + " }", + "#endif", + " yychar = (-1);", + " goto yyloop;", + " }", + "yyreduce:", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: state %d, reducing by rule %d (%s)\\n\",", + " YYPREFIX, yystate, yyn, yyrule[yyn]);", + "#endif", + " yym = yylen[yyn];", + " yyval = yyvsp[1-yym];", + " switch (yyn)", + " {", + 0 +}; + + +char *trailer[] = +{ + " }", + " yyssp -= yym;", + " yystate = *yyssp;", + " yyvsp -= yym;", + " yym = yylhs[yyn];", + " if (yystate == 0 && yym == 0)", + " {", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: after reduction, shifting from state 0 to\\", + " state %d\\n\", YYPREFIX, YYFINAL);", + "#endif", + " yystate = YYFINAL;", + " *++yyssp = YYFINAL;", + " *++yyvsp = yyval;", + " if (yychar < 0)", + " {", + " if ((yychar = yylex()) < 0) yychar = 0;", + "#if YYDEBUG", + " if (yydebug)", + " {", + " yys = 0;", + " if (yychar <= YYMAXTOKEN) yys = yyname[yychar];", + " if (!yys) yys = \"illegal-symbol\";", + " printf(\"%sdebug: state %d, reading %d (%s)\\n\",", + " YYPREFIX, YYFINAL, yychar, yys);", + " }", + "#endif", + " }", + " if (yychar == 0) goto yyaccept;", + " goto yyloop;", + " }", + " if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&", + " yyn <= YYTABLESIZE && yycheck[yyn] == yystate)", + " yystate = yytable[yyn];", + " else", + " yystate = yydgoto[yym];", + "#if YYDEBUG", + " if (yydebug)", + " printf(\"%sdebug: after reduction, shifting from state %d \\", + "to state %d\\n\", YYPREFIX, *yyssp, yystate);", + "#endif", + " if (yyssp >= yyss + yystacksize - 1)", + " {", + " goto yyoverflow;", + " }", + " *++yyssp = yystate;", + " *++yyvsp = yyval;", + " goto yyloop;", + "yyoverflow:", + " yyerror(\"yacc stack overflow\");", + "yyabort:", + " return (1);", + "yyaccept:", + " return (0);", + "}", + 0 +}; + + +write_section(section) +char *section[]; +{ + register int c; + register int i; + register char *s; + register FILE *f; + + f = code_file; + for (i = 0; s = section[i]; ++i) + { + ++outline; + while (c = *s) + { + putc(c, f); + ++s; + } + putc('\n', f); + } +} diff --git a/usr.bin/yacc/symtab.c b/usr.bin/yacc/symtab.c new file mode 100644 index 0000000..0c5f55c --- /dev/null +++ b/usr.bin/yacc/symtab.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)symtab.c 5.3 (Berkeley) 6/1/90"; +#endif /* not lint */ + +#include "defs.h" + +/* TABLE_SIZE is the number of entries in the symbol table. */ +/* TABLE_SIZE must be a power of two. */ + +#define TABLE_SIZE 1024 + + +bucket **symbol_table; +bucket *first_symbol; +bucket *last_symbol; + + +int +hash(name) +char *name; +{ + register char *s; + register int c, k; + + assert(name && *name); + s = name; + k = *s; + while (c = *++s) + k = (31*k + c) & (TABLE_SIZE - 1); + + return (k); +} + + +bucket * +make_bucket(name) +char *name; +{ + register bucket *bp; + + assert(name); + bp = (bucket *) MALLOC(sizeof(bucket)); + if (bp == 0) no_space(); + bp->link = 0; + bp->next = 0; + bp->name = MALLOC(strlen(name) + 1); + if (bp->name == 0) no_space(); + bp->tag = 0; + bp->value = UNDEFINED; + bp->index = 0; + bp->prec = 0; + bp-> class = UNKNOWN; + bp->assoc = TOKEN; + + if (bp->name == 0) no_space(); + strcpy(bp->name, name); + + return (bp); +} + + +bucket * +lookup(name) +char *name; +{ + register bucket *bp, **bpp; + + bpp = symbol_table + hash(name); + bp = *bpp; + + while (bp) + { + if (strcmp(name, bp->name) == 0) return (bp); + bpp = &bp->link; + bp = *bpp; + } + + *bpp = bp = make_bucket(name); + last_symbol->next = bp; + last_symbol = bp; + + return (bp); +} + + +create_symbol_table() +{ + register int i; + register bucket *bp; + + symbol_table = (bucket **) MALLOC(TABLE_SIZE*sizeof(bucket *)); + if (symbol_table == 0) no_space(); + for (i = 0; i < TABLE_SIZE; i++) + symbol_table[i] = 0; + + bp = make_bucket("error"); + bp->index = 1; + bp->class = TERM; + + first_symbol = bp; + last_symbol = bp; + symbol_table[hash("error")] = bp; +} + + +free_symbol_table() +{ + FREE(symbol_table); + symbol_table = 0; +} + + +free_symbols() +{ + register bucket *p, *q; + + for (p = first_symbol; p; p = q) + { + q = p->next; + FREE(p); + } +} diff --git a/usr.bin/yacc/test/error.output b/usr.bin/yacc/test/error.output new file mode 100644 index 0000000..0c4db62 --- /dev/null +++ b/usr.bin/yacc/test/error.output @@ -0,0 +1,27 @@ + 0 $accept : S $end + + 1 S : error + +state 0 + $accept : . S $end (0) + + error shift 1 + . error + + S goto 2 + + +state 1 + S : error . (1) + + . reduce 1 + + +state 2 + $accept : S . $end (0) + + $end accept + + +2 terminals, 2 nonterminals +2 grammar rules, 3 states diff --git a/usr.bin/yacc/test/error.tab.c b/usr.bin/yacc/test/error.tab.c new file mode 100644 index 0000000..ffc6e37 --- /dev/null +++ b/usr.bin/yacc/test/error.tab.c @@ -0,0 +1,275 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, +}; +short yylen[] = { 2, + 1, +}; +short yydefred[] = { 0, + 1, 0, +}; +short yydgoto[] = { 2, +}; +short yysindex[] = { -256, + 0, 0, +}; +short yyrindex[] = { 0, + 0, 0, +}; +short yygindex[] = { 0, +}; +#define YYTABLESIZE 0 +short yytable[] = { 1, +}; +short yycheck[] = { 256, +}; +#define YYFINAL 2 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 0 +#if YYDEBUG +char *yyname[] = { +"end-of-file", +}; +char *yyrule[] = { +"$accept : S", +"S : error", +}; +#endif +#ifndef YYSTYPE +typedef int YYSTYPE; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 4 "error.y" +main(){printf("yyparse() = %d\n",yyparse());} +yylex(){return-1;} +yyerror(s)char*s;{printf("%s\n",s);} +#line 80 "error.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/usr.bin/yacc/test/error.tab.h b/usr.bin/yacc/test/error.tab.h new file mode 100644 index 0000000..e69de29 diff --git a/usr.bin/yacc/test/error.y b/usr.bin/yacc/test/error.y new file mode 100644 index 0000000..41148ea --- /dev/null +++ b/usr.bin/yacc/test/error.y @@ -0,0 +1,6 @@ +%% +S: error +%% +main(){printf("yyparse() = %d\n",yyparse());} +yylex(){return-1;} +yyerror(s)char*s;{printf("%s\n",s);} diff --git a/usr.bin/yacc/test/ftp.output b/usr.bin/yacc/test/ftp.output new file mode 100644 index 0000000..f1ab4b2 --- /dev/null +++ b/usr.bin/yacc/test/ftp.output @@ -0,0 +1,1625 @@ + 0 $accept : cmd_list $end + + 1 cmd_list : + 2 | cmd_list cmd + 3 | cmd_list rcmd + + 4 cmd : USER SP username CRLF + 5 | PASS SP password CRLF + 6 | PORT SP host_port CRLF + 7 | PASV CRLF + 8 | TYPE SP type_code CRLF + 9 | STRU SP struct_code CRLF + 10 | MODE SP mode_code CRLF + 11 | ALLO SP NUMBER CRLF + 12 | ALLO SP NUMBER SP R SP NUMBER CRLF + 13 | RETR check_login SP pathname CRLF + 14 | STOR check_login SP pathname CRLF + 15 | APPE check_login SP pathname CRLF + 16 | NLST check_login CRLF + 17 | NLST check_login SP STRING CRLF + 18 | LIST check_login CRLF + 19 | LIST check_login SP pathname CRLF + 20 | STAT check_login SP pathname CRLF + 21 | STAT CRLF + 22 | DELE check_login SP pathname CRLF + 23 | RNTO SP pathname CRLF + 24 | ABOR CRLF + 25 | CWD check_login CRLF + 26 | CWD check_login SP pathname CRLF + 27 | HELP CRLF + 28 | HELP SP STRING CRLF + 29 | NOOP CRLF + 30 | MKD check_login SP pathname CRLF + 31 | RMD check_login SP pathname CRLF + 32 | PWD check_login CRLF + 33 | CDUP check_login CRLF + 34 | SITE SP HELP CRLF + 35 | SITE SP HELP SP STRING CRLF + 36 | SITE SP UMASK check_login CRLF + 37 | SITE SP UMASK check_login SP octal_number CRLF + 38 | SITE SP CHMOD check_login SP octal_number SP pathname CRLF + 39 | SITE SP IDLE CRLF + 40 | SITE SP IDLE SP NUMBER CRLF + 41 | STOU check_login SP pathname CRLF + 42 | SYST CRLF + 43 | SIZE check_login SP pathname CRLF + 44 | MDTM check_login SP pathname CRLF + 45 | QUIT CRLF + 46 | error CRLF + + 47 rcmd : RNFR check_login SP pathname CRLF + + 48 username : STRING + + 49 password : + 50 | STRING + + 51 byte_size : NUMBER + + 52 host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER + + 53 form_code : N + 54 | T + 55 | C + + 56 type_code : A + 57 | A SP form_code + 58 | E + 59 | E SP form_code + 60 | I + 61 | L + 62 | L SP byte_size + 63 | L byte_size + + 64 struct_code : F + 65 | R + 66 | P + + 67 mode_code : S + 68 | B + 69 | C + + 70 pathname : pathstring + + 71 pathstring : STRING + + 72 octal_number : NUMBER + + 73 check_login : + +state 0 + $accept : . cmd_list $end (0) + cmd_list : . (1) + + . reduce 1 + + cmd_list goto 1 + + +state 1 + $accept : cmd_list . $end (0) + cmd_list : cmd_list . cmd (2) + cmd_list : cmd_list . rcmd (3) + + $end accept + error shift 2 + USER shift 3 + PASS shift 4 + QUIT shift 5 + PORT shift 6 + PASV shift 7 + TYPE shift 8 + STRU shift 9 + MODE shift 10 + RETR shift 11 + STOR shift 12 + APPE shift 13 + ALLO shift 14 + RNFR shift 15 + RNTO shift 16 + ABOR shift 17 + DELE shift 18 + CWD shift 19 + LIST shift 20 + NLST shift 21 + SITE shift 22 + STAT shift 23 + HELP shift 24 + NOOP shift 25 + MKD shift 26 + RMD shift 27 + PWD shift 28 + CDUP shift 29 + STOU shift 30 + SYST shift 31 + SIZE shift 32 + MDTM shift 33 + . error + + cmd goto 34 + rcmd goto 35 + + +state 2 + cmd : error . CRLF (46) + + CRLF shift 36 + . error + + +state 3 + cmd : USER . SP username CRLF (4) + + SP shift 37 + . error + + +state 4 + cmd : PASS . SP password CRLF (5) + + SP shift 38 + . error + + +state 5 + cmd : QUIT . CRLF (45) + + CRLF shift 39 + . error + + +state 6 + cmd : PORT . SP host_port CRLF (6) + + SP shift 40 + . error + + +state 7 + cmd : PASV . CRLF (7) + + CRLF shift 41 + . error + + +state 8 + cmd : TYPE . SP type_code CRLF (8) + + SP shift 42 + . error + + +state 9 + cmd : STRU . SP struct_code CRLF (9) + + SP shift 43 + . error + + +state 10 + cmd : MODE . SP mode_code CRLF (10) + + SP shift 44 + . error + + +state 11 + cmd : RETR . check_login SP pathname CRLF (13) + check_login : . (73) + + . reduce 73 + + check_login goto 45 + + +state 12 + cmd : STOR . check_login SP pathname CRLF (14) + check_login : . (73) + + . reduce 73 + + check_login goto 46 + + +state 13 + cmd : APPE . check_login SP pathname CRLF (15) + check_login : . (73) + + . reduce 73 + + check_login goto 47 + + +state 14 + cmd : ALLO . SP NUMBER CRLF (11) + cmd : ALLO . SP NUMBER SP R SP NUMBER CRLF (12) + + SP shift 48 + . error + + +state 15 + rcmd : RNFR . check_login SP pathname CRLF (47) + check_login : . (73) + + . reduce 73 + + check_login goto 49 + + +state 16 + cmd : RNTO . SP pathname CRLF (23) + + SP shift 50 + . error + + +state 17 + cmd : ABOR . CRLF (24) + + CRLF shift 51 + . error + + +state 18 + cmd : DELE . check_login SP pathname CRLF (22) + check_login : . (73) + + . reduce 73 + + check_login goto 52 + + +state 19 + cmd : CWD . check_login CRLF (25) + cmd : CWD . check_login SP pathname CRLF (26) + check_login : . (73) + + . reduce 73 + + check_login goto 53 + + +state 20 + cmd : LIST . check_login CRLF (18) + cmd : LIST . check_login SP pathname CRLF (19) + check_login : . (73) + + . reduce 73 + + check_login goto 54 + + +state 21 + cmd : NLST . check_login CRLF (16) + cmd : NLST . check_login SP STRING CRLF (17) + check_login : . (73) + + . reduce 73 + + check_login goto 55 + + +state 22 + cmd : SITE . SP HELP CRLF (34) + cmd : SITE . SP HELP SP STRING CRLF (35) + cmd : SITE . SP UMASK check_login CRLF (36) + cmd : SITE . SP UMASK check_login SP octal_number CRLF (37) + cmd : SITE . SP CHMOD check_login SP octal_number SP pathname CRLF (38) + cmd : SITE . SP IDLE CRLF (39) + cmd : SITE . SP IDLE SP NUMBER CRLF (40) + + SP shift 56 + . error + + +state 23 + cmd : STAT . check_login SP pathname CRLF (20) + cmd : STAT . CRLF (21) + check_login : . (73) + + CRLF shift 57 + SP reduce 73 + + check_login goto 58 + + +state 24 + cmd : HELP . CRLF (27) + cmd : HELP . SP STRING CRLF (28) + + SP shift 59 + CRLF shift 60 + . error + + +state 25 + cmd : NOOP . CRLF (29) + + CRLF shift 61 + . error + + +state 26 + cmd : MKD . check_login SP pathname CRLF (30) + check_login : . (73) + + . reduce 73 + + check_login goto 62 + + +state 27 + cmd : RMD . check_login SP pathname CRLF (31) + check_login : . (73) + + . reduce 73 + + check_login goto 63 + + +state 28 + cmd : PWD . check_login CRLF (32) + check_login : . (73) + + . reduce 73 + + check_login goto 64 + + +state 29 + cmd : CDUP . check_login CRLF (33) + check_login : . (73) + + . reduce 73 + + check_login goto 65 + + +state 30 + cmd : STOU . check_login SP pathname CRLF (41) + check_login : . (73) + + . reduce 73 + + check_login goto 66 + + +state 31 + cmd : SYST . CRLF (42) + + CRLF shift 67 + . error + + +state 32 + cmd : SIZE . check_login SP pathname CRLF (43) + check_login : . (73) + + . reduce 73 + + check_login goto 68 + + +state 33 + cmd : MDTM . check_login SP pathname CRLF (44) + check_login : . (73) + + . reduce 73 + + check_login goto 69 + + +state 34 + cmd_list : cmd_list cmd . (2) + + . reduce 2 + + +state 35 + cmd_list : cmd_list rcmd . (3) + + . reduce 3 + + +state 36 + cmd : error CRLF . (46) + + . reduce 46 + + +state 37 + cmd : USER SP . username CRLF (4) + + STRING shift 70 + . error + + username goto 71 + + +state 38 + cmd : PASS SP . password CRLF (5) + password : . (49) + + STRING shift 72 + CRLF reduce 49 + + password goto 73 + + +state 39 + cmd : QUIT CRLF . (45) + + . reduce 45 + + +state 40 + cmd : PORT SP . host_port CRLF (6) + + NUMBER shift 74 + . error + + host_port goto 75 + + +state 41 + cmd : PASV CRLF . (7) + + . reduce 7 + + +state 42 + cmd : TYPE SP . type_code CRLF (8) + + A shift 76 + E shift 77 + I shift 78 + L shift 79 + . error + + type_code goto 80 + + +state 43 + cmd : STRU SP . struct_code CRLF (9) + + F shift 81 + P shift 82 + R shift 83 + . error + + struct_code goto 84 + + +state 44 + cmd : MODE SP . mode_code CRLF (10) + + B shift 85 + C shift 86 + S shift 87 + . error + + mode_code goto 88 + + +state 45 + cmd : RETR check_login . SP pathname CRLF (13) + + SP shift 89 + . error + + +state 46 + cmd : STOR check_login . SP pathname CRLF (14) + + SP shift 90 + . error + + +state 47 + cmd : APPE check_login . SP pathname CRLF (15) + + SP shift 91 + . error + + +state 48 + cmd : ALLO SP . NUMBER CRLF (11) + cmd : ALLO SP . NUMBER SP R SP NUMBER CRLF (12) + + NUMBER shift 92 + . error + + +state 49 + rcmd : RNFR check_login . SP pathname CRLF (47) + + SP shift 93 + . error + + +state 50 + cmd : RNTO SP . pathname CRLF (23) + + STRING shift 94 + . error + + pathname goto 95 + pathstring goto 96 + + +state 51 + cmd : ABOR CRLF . (24) + + . reduce 24 + + +state 52 + cmd : DELE check_login . SP pathname CRLF (22) + + SP shift 97 + . error + + +state 53 + cmd : CWD check_login . CRLF (25) + cmd : CWD check_login . SP pathname CRLF (26) + + SP shift 98 + CRLF shift 99 + . error + + +state 54 + cmd : LIST check_login . CRLF (18) + cmd : LIST check_login . SP pathname CRLF (19) + + SP shift 100 + CRLF shift 101 + . error + + +state 55 + cmd : NLST check_login . CRLF (16) + cmd : NLST check_login . SP STRING CRLF (17) + + SP shift 102 + CRLF shift 103 + . error + + +state 56 + cmd : SITE SP . HELP CRLF (34) + cmd : SITE SP . HELP SP STRING CRLF (35) + cmd : SITE SP . UMASK check_login CRLF (36) + cmd : SITE SP . UMASK check_login SP octal_number CRLF (37) + cmd : SITE SP . CHMOD check_login SP octal_number SP pathname CRLF (38) + cmd : SITE SP . IDLE CRLF (39) + cmd : SITE SP . IDLE SP NUMBER CRLF (40) + + HELP shift 104 + UMASK shift 105 + IDLE shift 106 + CHMOD shift 107 + . error + + +state 57 + cmd : STAT CRLF . (21) + + . reduce 21 + + +state 58 + cmd : STAT check_login . SP pathname CRLF (20) + + SP shift 108 + . error + + +state 59 + cmd : HELP SP . STRING CRLF (28) + + STRING shift 109 + . error + + +state 60 + cmd : HELP CRLF . (27) + + . reduce 27 + + +state 61 + cmd : NOOP CRLF . (29) + + . reduce 29 + + +state 62 + cmd : MKD check_login . SP pathname CRLF (30) + + SP shift 110 + . error + + +state 63 + cmd : RMD check_login . SP pathname CRLF (31) + + SP shift 111 + . error + + +state 64 + cmd : PWD check_login . CRLF (32) + + CRLF shift 112 + . error + + +state 65 + cmd : CDUP check_login . CRLF (33) + + CRLF shift 113 + . error + + +state 66 + cmd : STOU check_login . SP pathname CRLF (41) + + SP shift 114 + . error + + +state 67 + cmd : SYST CRLF . (42) + + . reduce 42 + + +state 68 + cmd : SIZE check_login . SP pathname CRLF (43) + + SP shift 115 + . error + + +state 69 + cmd : MDTM check_login . SP pathname CRLF (44) + + SP shift 116 + . error + + +state 70 + username : STRING . (48) + + . reduce 48 + + +state 71 + cmd : USER SP username . CRLF (4) + + CRLF shift 117 + . error + + +state 72 + password : STRING . (50) + + . reduce 50 + + +state 73 + cmd : PASS SP password . CRLF (5) + + CRLF shift 118 + . error + + +state 74 + host_port : NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 119 + . error + + +state 75 + cmd : PORT SP host_port . CRLF (6) + + CRLF shift 120 + . error + + +state 76 + type_code : A . (56) + type_code : A . SP form_code (57) + + SP shift 121 + CRLF reduce 56 + + +state 77 + type_code : E . (58) + type_code : E . SP form_code (59) + + SP shift 122 + CRLF reduce 58 + + +state 78 + type_code : I . (60) + + . reduce 60 + + +state 79 + type_code : L . (61) + type_code : L . SP byte_size (62) + type_code : L . byte_size (63) + + SP shift 123 + NUMBER shift 124 + CRLF reduce 61 + + byte_size goto 125 + + +state 80 + cmd : TYPE SP type_code . CRLF (8) + + CRLF shift 126 + . error + + +state 81 + struct_code : F . (64) + + . reduce 64 + + +state 82 + struct_code : P . (66) + + . reduce 66 + + +state 83 + struct_code : R . (65) + + . reduce 65 + + +state 84 + cmd : STRU SP struct_code . CRLF (9) + + CRLF shift 127 + . error + + +state 85 + mode_code : B . (68) + + . reduce 68 + + +state 86 + mode_code : C . (69) + + . reduce 69 + + +state 87 + mode_code : S . (67) + + . reduce 67 + + +state 88 + cmd : MODE SP mode_code . CRLF (10) + + CRLF shift 128 + . error + + +state 89 + cmd : RETR check_login SP . pathname CRLF (13) + + STRING shift 94 + . error + + pathname goto 129 + pathstring goto 96 + + +state 90 + cmd : STOR check_login SP . pathname CRLF (14) + + STRING shift 94 + . error + + pathname goto 130 + pathstring goto 96 + + +state 91 + cmd : APPE check_login SP . pathname CRLF (15) + + STRING shift 94 + . error + + pathname goto 131 + pathstring goto 96 + + +state 92 + cmd : ALLO SP NUMBER . CRLF (11) + cmd : ALLO SP NUMBER . SP R SP NUMBER CRLF (12) + + SP shift 132 + CRLF shift 133 + . error + + +state 93 + rcmd : RNFR check_login SP . pathname CRLF (47) + + STRING shift 94 + . error + + pathname goto 134 + pathstring goto 96 + + +state 94 + pathstring : STRING . (71) + + . reduce 71 + + +state 95 + cmd : RNTO SP pathname . CRLF (23) + + CRLF shift 135 + . error + + +state 96 + pathname : pathstring . (70) + + . reduce 70 + + +state 97 + cmd : DELE check_login SP . pathname CRLF (22) + + STRING shift 94 + . error + + pathname goto 136 + pathstring goto 96 + + +state 98 + cmd : CWD check_login SP . pathname CRLF (26) + + STRING shift 94 + . error + + pathname goto 137 + pathstring goto 96 + + +state 99 + cmd : CWD check_login CRLF . (25) + + . reduce 25 + + +state 100 + cmd : LIST check_login SP . pathname CRLF (19) + + STRING shift 94 + . error + + pathname goto 138 + pathstring goto 96 + + +state 101 + cmd : LIST check_login CRLF . (18) + + . reduce 18 + + +state 102 + cmd : NLST check_login SP . STRING CRLF (17) + + STRING shift 139 + . error + + +state 103 + cmd : NLST check_login CRLF . (16) + + . reduce 16 + + +state 104 + cmd : SITE SP HELP . CRLF (34) + cmd : SITE SP HELP . SP STRING CRLF (35) + + SP shift 140 + CRLF shift 141 + . error + + +state 105 + cmd : SITE SP UMASK . check_login CRLF (36) + cmd : SITE SP UMASK . check_login SP octal_number CRLF (37) + check_login : . (73) + + . reduce 73 + + check_login goto 142 + + +state 106 + cmd : SITE SP IDLE . CRLF (39) + cmd : SITE SP IDLE . SP NUMBER CRLF (40) + + SP shift 143 + CRLF shift 144 + . error + + +state 107 + cmd : SITE SP CHMOD . check_login SP octal_number SP pathname CRLF (38) + check_login : . (73) + + . reduce 73 + + check_login goto 145 + + +state 108 + cmd : STAT check_login SP . pathname CRLF (20) + + STRING shift 94 + . error + + pathname goto 146 + pathstring goto 96 + + +state 109 + cmd : HELP SP STRING . CRLF (28) + + CRLF shift 147 + . error + + +state 110 + cmd : MKD check_login SP . pathname CRLF (30) + + STRING shift 94 + . error + + pathname goto 148 + pathstring goto 96 + + +state 111 + cmd : RMD check_login SP . pathname CRLF (31) + + STRING shift 94 + . error + + pathname goto 149 + pathstring goto 96 + + +state 112 + cmd : PWD check_login CRLF . (32) + + . reduce 32 + + +state 113 + cmd : CDUP check_login CRLF . (33) + + . reduce 33 + + +state 114 + cmd : STOU check_login SP . pathname CRLF (41) + + STRING shift 94 + . error + + pathname goto 150 + pathstring goto 96 + + +state 115 + cmd : SIZE check_login SP . pathname CRLF (43) + + STRING shift 94 + . error + + pathname goto 151 + pathstring goto 96 + + +state 116 + cmd : MDTM check_login SP . pathname CRLF (44) + + STRING shift 94 + . error + + pathname goto 152 + pathstring goto 96 + + +state 117 + cmd : USER SP username CRLF . (4) + + . reduce 4 + + +state 118 + cmd : PASS SP password CRLF . (5) + + . reduce 5 + + +state 119 + host_port : NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 153 + . error + + +state 120 + cmd : PORT SP host_port CRLF . (6) + + . reduce 6 + + +state 121 + type_code : A SP . form_code (57) + + C shift 154 + N shift 155 + T shift 156 + . error + + form_code goto 157 + + +state 122 + type_code : E SP . form_code (59) + + C shift 154 + N shift 155 + T shift 156 + . error + + form_code goto 158 + + +state 123 + type_code : L SP . byte_size (62) + + NUMBER shift 124 + . error + + byte_size goto 159 + + +state 124 + byte_size : NUMBER . (51) + + . reduce 51 + + +state 125 + type_code : L byte_size . (63) + + . reduce 63 + + +state 126 + cmd : TYPE SP type_code CRLF . (8) + + . reduce 8 + + +state 127 + cmd : STRU SP struct_code CRLF . (9) + + . reduce 9 + + +state 128 + cmd : MODE SP mode_code CRLF . (10) + + . reduce 10 + + +state 129 + cmd : RETR check_login SP pathname . CRLF (13) + + CRLF shift 160 + . error + + +state 130 + cmd : STOR check_login SP pathname . CRLF (14) + + CRLF shift 161 + . error + + +state 131 + cmd : APPE check_login SP pathname . CRLF (15) + + CRLF shift 162 + . error + + +state 132 + cmd : ALLO SP NUMBER SP . R SP NUMBER CRLF (12) + + R shift 163 + . error + + +state 133 + cmd : ALLO SP NUMBER CRLF . (11) + + . reduce 11 + + +state 134 + rcmd : RNFR check_login SP pathname . CRLF (47) + + CRLF shift 164 + . error + + +state 135 + cmd : RNTO SP pathname CRLF . (23) + + . reduce 23 + + +state 136 + cmd : DELE check_login SP pathname . CRLF (22) + + CRLF shift 165 + . error + + +state 137 + cmd : CWD check_login SP pathname . CRLF (26) + + CRLF shift 166 + . error + + +state 138 + cmd : LIST check_login SP pathname . CRLF (19) + + CRLF shift 167 + . error + + +state 139 + cmd : NLST check_login SP STRING . CRLF (17) + + CRLF shift 168 + . error + + +state 140 + cmd : SITE SP HELP SP . STRING CRLF (35) + + STRING shift 169 + . error + + +state 141 + cmd : SITE SP HELP CRLF . (34) + + . reduce 34 + + +state 142 + cmd : SITE SP UMASK check_login . CRLF (36) + cmd : SITE SP UMASK check_login . SP octal_number CRLF (37) + + SP shift 170 + CRLF shift 171 + . error + + +state 143 + cmd : SITE SP IDLE SP . NUMBER CRLF (40) + + NUMBER shift 172 + . error + + +state 144 + cmd : SITE SP IDLE CRLF . (39) + + . reduce 39 + + +state 145 + cmd : SITE SP CHMOD check_login . SP octal_number SP pathname CRLF (38) + + SP shift 173 + . error + + +state 146 + cmd : STAT check_login SP pathname . CRLF (20) + + CRLF shift 174 + . error + + +state 147 + cmd : HELP SP STRING CRLF . (28) + + . reduce 28 + + +state 148 + cmd : MKD check_login SP pathname . CRLF (30) + + CRLF shift 175 + . error + + +state 149 + cmd : RMD check_login SP pathname . CRLF (31) + + CRLF shift 176 + . error + + +state 150 + cmd : STOU check_login SP pathname . CRLF (41) + + CRLF shift 177 + . error + + +state 151 + cmd : SIZE check_login SP pathname . CRLF (43) + + CRLF shift 178 + . error + + +state 152 + cmd : MDTM check_login SP pathname . CRLF (44) + + CRLF shift 179 + . error + + +state 153 + host_port : NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 180 + . error + + +state 154 + form_code : C . (55) + + . reduce 55 + + +state 155 + form_code : N . (53) + + . reduce 53 + + +state 156 + form_code : T . (54) + + . reduce 54 + + +state 157 + type_code : A SP form_code . (57) + + . reduce 57 + + +state 158 + type_code : E SP form_code . (59) + + . reduce 59 + + +state 159 + type_code : L SP byte_size . (62) + + . reduce 62 + + +state 160 + cmd : RETR check_login SP pathname CRLF . (13) + + . reduce 13 + + +state 161 + cmd : STOR check_login SP pathname CRLF . (14) + + . reduce 14 + + +state 162 + cmd : APPE check_login SP pathname CRLF . (15) + + . reduce 15 + + +state 163 + cmd : ALLO SP NUMBER SP R . SP NUMBER CRLF (12) + + SP shift 181 + . error + + +state 164 + rcmd : RNFR check_login SP pathname CRLF . (47) + + . reduce 47 + + +state 165 + cmd : DELE check_login SP pathname CRLF . (22) + + . reduce 22 + + +state 166 + cmd : CWD check_login SP pathname CRLF . (26) + + . reduce 26 + + +state 167 + cmd : LIST check_login SP pathname CRLF . (19) + + . reduce 19 + + +state 168 + cmd : NLST check_login SP STRING CRLF . (17) + + . reduce 17 + + +state 169 + cmd : SITE SP HELP SP STRING . CRLF (35) + + CRLF shift 182 + . error + + +state 170 + cmd : SITE SP UMASK check_login SP . octal_number CRLF (37) + + NUMBER shift 183 + . error + + octal_number goto 184 + + +state 171 + cmd : SITE SP UMASK check_login CRLF . (36) + + . reduce 36 + + +state 172 + cmd : SITE SP IDLE SP NUMBER . CRLF (40) + + CRLF shift 185 + . error + + +state 173 + cmd : SITE SP CHMOD check_login SP . octal_number SP pathname CRLF (38) + + NUMBER shift 183 + . error + + octal_number goto 186 + + +state 174 + cmd : STAT check_login SP pathname CRLF . (20) + + . reduce 20 + + +state 175 + cmd : MKD check_login SP pathname CRLF . (30) + + . reduce 30 + + +state 176 + cmd : RMD check_login SP pathname CRLF . (31) + + . reduce 31 + + +state 177 + cmd : STOU check_login SP pathname CRLF . (41) + + . reduce 41 + + +state 178 + cmd : SIZE check_login SP pathname CRLF . (43) + + . reduce 43 + + +state 179 + cmd : MDTM check_login SP pathname CRLF . (44) + + . reduce 44 + + +state 180 + host_port : NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 187 + . error + + +state 181 + cmd : ALLO SP NUMBER SP R SP . NUMBER CRLF (12) + + NUMBER shift 188 + . error + + +state 182 + cmd : SITE SP HELP SP STRING CRLF . (35) + + . reduce 35 + + +state 183 + octal_number : NUMBER . (72) + + . reduce 72 + + +state 184 + cmd : SITE SP UMASK check_login SP octal_number . CRLF (37) + + CRLF shift 189 + . error + + +state 185 + cmd : SITE SP IDLE SP NUMBER CRLF . (40) + + . reduce 40 + + +state 186 + cmd : SITE SP CHMOD check_login SP octal_number . SP pathname CRLF (38) + + SP shift 190 + . error + + +state 187 + host_port : NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 191 + . error + + +state 188 + cmd : ALLO SP NUMBER SP R SP NUMBER . CRLF (12) + + CRLF shift 192 + . error + + +state 189 + cmd : SITE SP UMASK check_login SP octal_number CRLF . (37) + + . reduce 37 + + +state 190 + cmd : SITE SP CHMOD check_login SP octal_number SP . pathname CRLF (38) + + STRING shift 94 + . error + + pathname goto 193 + pathstring goto 96 + + +state 191 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER COMMA NUMBER (52) + + NUMBER shift 194 + . error + + +state 192 + cmd : ALLO SP NUMBER SP R SP NUMBER CRLF . (12) + + . reduce 12 + + +state 193 + cmd : SITE SP CHMOD check_login SP octal_number SP pathname . CRLF (38) + + CRLF shift 195 + . error + + +state 194 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER COMMA NUMBER (52) + + COMMA shift 196 + . error + + +state 195 + cmd : SITE SP CHMOD check_login SP octal_number SP pathname CRLF . (38) + + . reduce 38 + + +state 196 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER COMMA NUMBER (52) + + NUMBER shift 197 + . error + + +state 197 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . COMMA NUMBER (52) + + COMMA shift 198 + . error + + +state 198 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA . NUMBER (52) + + NUMBER shift 199 + . error + + +state 199 + host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER . (52) + + . reduce 52 + + +65 terminals, 16 nonterminals +74 grammar rules, 200 states diff --git a/usr.bin/yacc/test/ftp.tab.c b/usr.bin/yacc/test/ftp.tab.c new file mode 100644 index 0000000..c9794ed --- /dev/null +++ b/usr.bin/yacc/test/ftp.tab.c @@ -0,0 +1,1743 @@ +#ifndef lint +static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#line 26 "ftp.y" + +#ifndef lint +static char sccsid[] = "@(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89"; +#endif /* not lint */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern char *globerr; +extern int usedefault; +extern int transflag; +extern char tmpline[]; +char **glob(); + +static int cmd_type; +static int cmd_form; +static int cmd_bytesz; +char cbuf[512]; +char *fromname; + +char *index(); +#line 60 "ftp.tab.c" +#define A 257 +#define B 258 +#define C 259 +#define E 260 +#define F 261 +#define I 262 +#define L 263 +#define N 264 +#define P 265 +#define R 266 +#define S 267 +#define T 268 +#define SP 269 +#define CRLF 270 +#define COMMA 271 +#define STRING 272 +#define NUMBER 273 +#define USER 274 +#define PASS 275 +#define ACCT 276 +#define REIN 277 +#define QUIT 278 +#define PORT 279 +#define PASV 280 +#define TYPE 281 +#define STRU 282 +#define MODE 283 +#define RETR 284 +#define STOR 285 +#define APPE 286 +#define MLFL 287 +#define MAIL 288 +#define MSND 289 +#define MSOM 290 +#define MSAM 291 +#define MRSQ 292 +#define MRCP 293 +#define ALLO 294 +#define REST 295 +#define RNFR 296 +#define RNTO 297 +#define ABOR 298 +#define DELE 299 +#define CWD 300 +#define LIST 301 +#define NLST 302 +#define SITE 303 +#define STAT 304 +#define HELP 305 +#define NOOP 306 +#define MKD 307 +#define RMD 308 +#define PWD 309 +#define CDUP 310 +#define STOU 311 +#define SMNT 312 +#define SYST 313 +#define SIZE 314 +#define MDTM 315 +#define UMASK 316 +#define IDLE 317 +#define CHMOD 318 +#define LEXERR 319 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, + 12, 5, 13, 13, 13, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 8, 8, 8, 10, + 14, 11, 9, +}; +short yylen[] = { 2, + 0, 2, 2, 4, 4, 4, 2, 4, 4, 4, + 4, 8, 5, 5, 5, 3, 5, 3, 5, 5, + 2, 5, 4, 2, 3, 5, 2, 4, 2, 5, + 5, 3, 3, 4, 6, 5, 7, 9, 4, 6, + 5, 2, 5, 5, 2, 2, 5, 1, 0, 1, + 1, 11, 1, 1, 1, 1, 3, 1, 3, 1, + 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, +}; +short yydefred[] = { 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 73, 73, 0, 73, 0, 0, 73, 73, 73, + 73, 0, 0, 0, 0, 73, 73, 73, 73, 73, + 0, 73, 73, 2, 3, 46, 0, 0, 45, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 0, 0, 21, 0, 0, 27, + 29, 0, 0, 0, 0, 0, 42, 0, 0, 48, + 0, 50, 0, 0, 0, 0, 0, 60, 0, 0, + 64, 66, 65, 0, 68, 69, 67, 0, 0, 0, + 0, 0, 0, 71, 0, 70, 0, 0, 25, 0, + 18, 0, 16, 0, 73, 0, 73, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 4, 5, 0, 6, + 0, 0, 0, 51, 63, 8, 9, 10, 0, 0, + 0, 0, 11, 0, 23, 0, 0, 0, 0, 0, + 34, 0, 0, 39, 0, 0, 28, 0, 0, 0, + 0, 0, 0, 55, 53, 54, 57, 59, 62, 13, + 14, 15, 0, 47, 22, 26, 19, 17, 0, 0, + 36, 0, 0, 20, 30, 31, 41, 43, 44, 0, + 0, 35, 72, 0, 40, 0, 0, 0, 37, 0, + 0, 12, 0, 0, 38, 0, 0, 0, 52, +}; +short yydgoto[] = { 1, + 34, 35, 71, 73, 75, 80, 84, 88, 45, 95, + 184, 125, 157, 96, +}; +short yysindex[] = { 0, + -224, -247, -239, -236, -232, -222, -204, -200, -181, -177, + 0, 0, 0, -166, 0, -161, -199, 0, 0, 0, + 0, -160, -159, -264, -158, 0, 0, 0, 0, 0, + -157, 0, 0, 0, 0, 0, -167, -162, 0, -156, + 0, -250, -198, -165, -155, -154, -153, -151, -150, -152, + 0, -145, -252, -229, -217, -302, 0, -144, -146, 0, + 0, -142, -141, -140, -139, -137, 0, -136, -135, 0, + -134, 0, -133, -132, -130, -131, -128, 0, -249, -127, + 0, 0, 0, -126, 0, 0, 0, -125, -152, -152, + -152, -205, -152, 0, -124, 0, -152, -152, 0, -152, + 0, -143, 0, -173, 0, -171, 0, -152, -123, -152, + -152, 0, 0, -152, -152, -152, 0, 0, -138, 0, + -164, -164, -122, 0, 0, 0, 0, 0, -121, -120, + -118, -148, 0, -117, 0, -116, -115, -114, -113, -112, + 0, -163, -111, 0, -110, -109, 0, -107, -106, -105, + -104, -103, -129, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -101, 0, 0, 0, 0, 0, -100, -102, + 0, -98, -102, 0, 0, 0, 0, 0, 0, -99, + -97, 0, 0, -95, 0, -96, -94, -92, 0, -152, + -93, 0, -91, -90, 0, -88, -87, -86, 0, +}; +short yyrindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -83, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -82, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -81, -80, 0, -158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +short yygindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, -89, + -25, 35, 47, 0, +}; +#define YYTABLESIZE 190 +short yytable[] = { 129, + 130, 131, 104, 134, 59, 60, 76, 136, 137, 77, + 138, 78, 79, 105, 106, 107, 98, 99, 146, 123, + 148, 149, 36, 124, 150, 151, 152, 46, 47, 37, + 49, 2, 38, 52, 53, 54, 55, 39, 58, 100, + 101, 62, 63, 64, 65, 66, 40, 68, 69, 3, + 4, 102, 103, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 81, 132, 133, 41, 82, 83, 42, 14, + 51, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 43, 31, 32, + 33, 44, 85, 86, 154, 140, 141, 143, 144, 155, + 193, 87, 48, 156, 70, 170, 171, 50, 56, 72, + 57, 61, 67, 89, 90, 91, 74, 163, 93, 94, + 142, 92, 145, 97, 108, 109, 110, 111, 139, 112, + 113, 114, 115, 116, 153, 117, 118, 121, 119, 120, + 122, 180, 126, 127, 128, 135, 147, 186, 160, 161, + 124, 162, 164, 165, 166, 167, 168, 159, 173, 169, + 174, 172, 175, 176, 177, 178, 179, 181, 158, 182, + 183, 185, 190, 187, 189, 188, 191, 192, 195, 194, + 196, 0, 0, 198, 197, 73, 199, 49, 56, 58, +}; +short yycheck[] = { 89, + 90, 91, 305, 93, 269, 270, 257, 97, 98, 260, + 100, 262, 263, 316, 317, 318, 269, 270, 108, 269, + 110, 111, 270, 273, 114, 115, 116, 12, 13, 269, + 15, 256, 269, 18, 19, 20, 21, 270, 23, 269, + 270, 26, 27, 28, 29, 30, 269, 32, 33, 274, + 275, 269, 270, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 261, 269, 270, 270, 265, 266, 269, 294, + 270, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 269, 313, 314, + 315, 269, 258, 259, 259, 269, 270, 269, 270, 264, + 190, 267, 269, 268, 272, 269, 270, 269, 269, 272, + 270, 270, 270, 269, 269, 269, 273, 266, 269, 272, + 105, 273, 107, 269, 269, 272, 269, 269, 272, 270, + 270, 269, 269, 269, 273, 270, 270, 269, 271, 270, + 269, 271, 270, 270, 270, 270, 270, 173, 270, 270, + 273, 270, 270, 270, 270, 270, 270, 123, 269, 272, + 270, 273, 270, 270, 270, 270, 270, 269, 122, 270, + 273, 270, 269, 273, 270, 273, 271, 270, 270, 273, + 271, -1, -1, 271, 273, 269, 273, 270, 270, 270, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 319 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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","E","F","I","L","N", +"P","R","S","T","SP","CRLF","COMMA","STRING","NUMBER","USER","PASS","ACCT", +"REIN","QUIT","PORT","PASV","TYPE","STRU","MODE","RETR","STOR","APPE","MLFL", +"MAIL","MSND","MSOM","MSAM","MRSQ","MRCP","ALLO","REST","RNFR","RNTO","ABOR", +"DELE","CWD","LIST","NLST","SITE","STAT","HELP","NOOP","MKD","RMD","PWD","CDUP", +"STOU","SMNT","SYST","SIZE","MDTM","UMASK","IDLE","CHMOD","LEXERR", +}; +char *yyrule[] = { +"$accept : cmd_list", +"cmd_list :", +"cmd_list : cmd_list cmd", +"cmd_list : cmd_list rcmd", +"cmd : USER SP username CRLF", +"cmd : PASS SP password CRLF", +"cmd : PORT SP host_port CRLF", +"cmd : PASV CRLF", +"cmd : TYPE SP type_code CRLF", +"cmd : STRU SP struct_code CRLF", +"cmd : MODE SP mode_code CRLF", +"cmd : ALLO SP NUMBER CRLF", +"cmd : ALLO SP NUMBER SP R SP NUMBER CRLF", +"cmd : RETR check_login SP pathname CRLF", +"cmd : STOR check_login SP pathname CRLF", +"cmd : APPE check_login SP pathname CRLF", +"cmd : NLST check_login CRLF", +"cmd : NLST check_login SP STRING CRLF", +"cmd : LIST check_login CRLF", +"cmd : LIST check_login SP pathname CRLF", +"cmd : STAT check_login SP pathname CRLF", +"cmd : STAT CRLF", +"cmd : DELE check_login SP pathname CRLF", +"cmd : RNTO SP pathname CRLF", +"cmd : ABOR CRLF", +"cmd : CWD check_login CRLF", +"cmd : CWD check_login SP pathname CRLF", +"cmd : HELP CRLF", +"cmd : HELP SP STRING CRLF", +"cmd : NOOP CRLF", +"cmd : MKD check_login SP pathname CRLF", +"cmd : RMD check_login SP pathname CRLF", +"cmd : PWD check_login CRLF", +"cmd : CDUP check_login CRLF", +"cmd : SITE SP HELP CRLF", +"cmd : SITE SP HELP SP STRING CRLF", +"cmd : SITE SP UMASK check_login CRLF", +"cmd : SITE SP UMASK check_login SP octal_number CRLF", +"cmd : SITE SP CHMOD check_login SP octal_number SP pathname CRLF", +"cmd : SITE SP IDLE CRLF", +"cmd : SITE SP IDLE SP NUMBER CRLF", +"cmd : STOU check_login SP pathname CRLF", +"cmd : SYST CRLF", +"cmd : SIZE check_login SP pathname CRLF", +"cmd : MDTM check_login SP pathname CRLF", +"cmd : QUIT CRLF", +"cmd : error CRLF", +"rcmd : RNFR check_login SP pathname CRLF", +"username : STRING", +"password :", +"password : STRING", +"byte_size : NUMBER", +"host_port : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER", +"form_code : N", +"form_code : T", +"form_code : C", +"type_code : A", +"type_code : A SP form_code", +"type_code : E", +"type_code : E SP form_code", +"type_code : I", +"type_code : L", +"type_code : L SP byte_size", +"type_code : L byte_size", +"struct_code : F", +"struct_code : R", +"struct_code : P", +"mode_code : S", +"mode_code : B", +"mode_code : C", +"pathname : pathstring", +"pathstring : STRING", +"octal_number : NUMBER", +"check_login :", +}; +#endif +#ifndef YYSTYPE +typedef int YYSTYPE; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#define yystacksize YYSTACKSIZE +#line 658 "ftp.y" + +extern jmp_buf errcatch; + +#define CMD 0 /* beginning of command */ +#define ARGS 1 /* expect miscellaneous arguments */ +#define STR1 2 /* expect SP followed by STRING */ +#define STR2 3 /* expect STRING */ +#define OSTR 4 /* optional SP then STRING */ +#define ZSTR1 5 /* SP then optional STRING */ +#define ZSTR2 6 /* optional STRING after SP */ +#define SITECMD 7 /* SITE command */ +#define NSTR 8 /* Number followed by a string */ + +struct tab { + char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + char *help; +}; + +struct tab cmdtab[] = { /* In order defined in RFC 765 */ + { "USER", USER, STR1, 1, " username" }, + { "PASS", PASS, ZSTR1, 1, " password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, + { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, + { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, + { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, + { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, " file-name" }, + { "STOR", STOR, STR1, 1, " file-name" }, + { "APPE", APPE, STR1, 1, " file-name" }, + { "MLFL", MLFL, OSTR, 0, "(mail file)" }, + { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, + { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, + { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, + { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, + { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, + { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 0, "(restart command)" }, + { "RNFR", RNFR, STR1, 1, " file-name" }, + { "RNTO", RNTO, STR1, 1, " file-name" }, + { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, + { "DELE", DELE, STR1, 1, " file-name" }, + { "CWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "XCWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "LIST", LIST, OSTR, 1, "[ path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, + { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 1, "[ path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "NOOP", NOOP, ARGS, 1, "" }, + { "MKD", MKD, STR1, 1, " path-name" }, + { "XMKD", MKD, STR1, 1, " path-name" }, + { "RMD", RMD, STR1, 1, " path-name" }, + { "XRMD", RMD, STR1, 1, " path-name" }, + { "PWD", PWD, ARGS, 1, "(return current directory)" }, + { "XPWD", PWD, ARGS, 1, "(return current directory)" }, + { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "STOU", STOU, STR1, 1, " file-name" }, + { "SIZE", SIZE, OSTR, 1, " path-name" }, + { "MDTM", MDTM, OSTR, 1, " path-name" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, + { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, + { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab * +lookup(p, cmd) + register struct tab *p; + char *cmd; +{ + + for (; p->name != NULL; p++) + if (strcmp(cmd, p->name) == 0) + return (p); + return (0); +} + +#include + +/* + * getline - a hacked up version of fgets to ignore TELNET escape codes. + */ +char * +getline(s, n, iop) + char *s; + register FILE *iop; +{ + register c; + register char *cs; + + cs = s; +/* tmpline may contain saved command from urgent mode interruption */ + for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { + *cs++ = tmpline[c]; + if (tmpline[c] == '\n') { + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + tmpline[0] = '\0'; + return(s); + } + if (c == 0) + tmpline[0] = '\0'; + } + while ((c = getc(iop)) != EOF) { + c &= 0377; + if (c == IAC) { + if ((c = getc(iop)) != EOF) { + c &= 0377; + switch (c) { + case WILL: + case WONT: + c = getc(iop); + printf("%c%c%c", IAC, DONT, 0377&c); + (void) fflush(stdout); + continue; + case DO: + case DONT: + c = getc(iop); + printf("%c%c%c", IAC, WONT, 0377&c); + (void) fflush(stdout); + continue; + case IAC: + break; + default: + continue; /* ignore command */ + } + } + } + *cs++ = c; + if (--n <= 0 || c == '\n') + break; + } + if (c == EOF && cs == s) + return (NULL); + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + return (s); +} + +static int +toolong() +{ + time_t now; + extern char *ctime(); + extern time_t time(); + + reply(421, + "Timeout (%d seconds): closing control connection.", timeout); + (void) time(&now); + if (logging) { + syslog(LOG_INFO, + "User %s timed out after %d seconds at %s", + (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); + } + dologout(1); +} + +yylex() +{ + static int cpos, state; + register char *cp, *cp2; + register struct tab *p; + int n; + char c, *strpbrk(); + char *copy(); + + for (;;) { + switch (state) { + + case CMD: + (void) signal(SIGALRM, toolong); + (void) alarm((unsigned) timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); +#ifdef SETPROCTITLE + if (strncasecmp(cbuf, "PASS", 4) != NULL) + setproctitle("%s: %s", proctitle, cbuf); +#endif /* SETPROCTITLE */ + if ((cp = index(cbuf, '\r'))) { + *cp++ = '\n'; + *cp = '\0'; + } + if ((cp = strpbrk(cbuf, " \n"))) + cpos = cp - cbuf; + if (cpos == 0) + cpos = 4; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cbuf); + p = lookup(cmdtab, cbuf); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + break; + + case SITECMD: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + cp = &cbuf[cpos]; + if ((cp2 = strpbrk(cp, " \n"))) + cpos = cp2 - cbuf; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cp); + p = lookup(sitetab, cp); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + state = CMD; + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + state = CMD; + break; + + case OSTR: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR1: + case ZSTR1: + dostr1: + if (cbuf[cpos] == ' ') { + cpos++; + state = state == OSTR ? STR2 : ++state; + return (SP); + } + break; + + case ZSTR2: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR2: + cp = &cbuf[cpos]; + n = strlen(cp); + cpos += n - 1; + /* + * Make sure the string is nonempty and \n terminated. + */ + if (n > 1 && cbuf[cpos] == '\n') { + cbuf[cpos] = '\0'; + *(char **)&yylval = copy(cp); + cbuf[cpos] = '\n'; + state = ARGS; + return (STRING); + } + break; + + case NSTR: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + state = STR1; + return (NUMBER); + } + state = STR1; + goto dostr1; + + case ARGS: + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + return (NUMBER); + } + switch (cbuf[cpos++]) { + + case '\n': + state = CMD; + return (CRLF); + + case ' ': + return (SP); + + case ',': + return (COMMA); + + case 'A': + case 'a': + return (A); + + case 'B': + case 'b': + return (B); + + case 'C': + case 'c': + return (C); + + case 'E': + case 'e': + return (E); + + case 'F': + case 'f': + return (F); + + case 'I': + case 'i': + return (I); + + case 'L': + case 'l': + return (L); + + case 'N': + case 'n': + return (N); + + case 'P': + case 'p': + return (P); + + case 'R': + case 'r': + return (R); + + case 'S': + case 's': + return (S); + + case 'T': + case 't': + return (T); + + } + break; + + default: + fatal("Unknown state in scanner."); + } + yyerror((char *) 0); + state = CMD; + longjmp(errcatch,0); + } +} + +upper(s) + register char *s; +{ + while (*s != '\0') { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +char * +copy(s) + char *s; +{ + char *p; + extern char *malloc(), *strcpy(); + + p = malloc((unsigned) strlen(s) + 1); + if (p == NULL) + fatal("Ran out of memory."); + (void) strcpy(p, s); + return (p); +} + +help(ctab, s) + struct tab *ctab; + char *s; +{ + register struct tab *c; + register int width, NCMDS; + char *type; + + if (ctab == sitetab) + type = "SITE "; + else + type = ""; + width = 0, NCMDS = 0; + for (c = ctab; c->name != NULL; c++) { + int len = strlen(c->name); + + if (len > width) + width = len; + NCMDS++; + } + width = (width + 8) &~ 7; + if (s == 0) { + register int i, j, w; + int columns, lines; + + lreply(214, "The following %scommands are recognized %s.", + type, "(* =>'s unimplemented)"); + columns = 76 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + printf(" "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + printf("%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + putchar(' '); + w++; + } + } + printf("\r\n"); + } + (void) fflush(stdout); + reply(214, "Direct comments to ftp-bugs@%s.", hostname); + return; + } + upper(s); + c = lookup(ctab, s); + if (c == (struct tab *)0) { + reply(502, "Unknown command %s.", s); + return; + } + if (c->implemented) + reply(214, "Syntax: %s%s %s", type, c->name, c->help); + else + reply(214, "%s%-*s\t%s; unimplemented.", type, width, + c->name, c->help); +} + +sizecmd(filename) +char *filename; +{ + switch (type) { + case TYPE_L: + case TYPE_I: { + struct stat stbuf; + if (stat(filename, &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) + reply(550, "%s: not a plain file.", filename); + else + reply(213, "%lu", stbuf.st_size); + break;} + case TYPE_A: { + FILE *fin; + register int c, count; + struct stat stbuf; + fin = fopen(filename, "r"); + if (fin == NULL) { + perror_reply(550, filename); + return; + } + if (fstat(fileno(fin), &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", filename); + (void) fclose(fin); + return; + } + + count = 0; + while((c=getc(fin)) != EOF) { + if (c == '\n') /* will get expanded to \r\n */ + count++; + count++; + } + (void) fclose(fin); + + reply(213, "%ld", count); + break;} + default: + reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); + } +} +#line 908 "ftp.tab.c" +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 2: +#line 99 "ftp.y" + { + fromname = (char *) 0; + } +break; +case 4: +#line 106 "ftp.y" + { + user((char *) yyvsp[-1]); + free((char *) yyvsp[-1]); + } +break; +case 5: +#line 111 "ftp.y" + { + pass((char *) yyvsp[-1]); + free((char *) yyvsp[-1]); + } +break; +case 6: +#line 116 "ftp.y" + { + usedefault = 0; + if (pdata >= 0) { + (void) close(pdata); + pdata = -1; + } + reply(200, "PORT command successful."); + } +break; +case 7: +#line 125 "ftp.y" + { + passive(); + } +break; +case 8: +#line 129 "ftp.y" + { + switch (cmd_type) { + + case TYPE_A: + if (cmd_form == FORM_N) { + reply(200, "Type set to A."); + type = cmd_type; + form = cmd_form; + } else + reply(504, "Form must be N."); + break; + + case TYPE_E: + reply(504, "Type E not implemented."); + break; + + case TYPE_I: + reply(200, "Type set to I."); + type = cmd_type; + break; + + case TYPE_L: +#if NBBY == 8 + if (cmd_bytesz == 8) { + reply(200, + "Type set to L (byte size 8)."); + type = cmd_type; + } else + reply(504, "Byte size must be 8."); +#else /* NBBY == 8 */ + UNIMPLEMENTED for NBBY != 8 +#endif /* NBBY == 8 */ + } + } +break; +case 9: +#line 164 "ftp.y" + { + switch (yyvsp[-1]) { + + case STRU_F: + reply(200, "STRU F ok."); + break; + + default: + reply(504, "Unimplemented STRU type."); + } + } +break; +case 10: +#line 176 "ftp.y" + { + switch (yyvsp[-1]) { + + case MODE_S: + reply(200, "MODE S ok."); + break; + + default: + reply(502, "Unimplemented MODE type."); + } + } +break; +case 11: +#line 188 "ftp.y" + { + reply(202, "ALLO command ignored."); + } +break; +case 12: +#line 192 "ftp.y" + { + reply(202, "ALLO command ignored."); + } +break; +case 13: +#line 196 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + retrieve((char *) 0, (char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 14: +#line 203 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "w", 0); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 15: +#line 210 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "a", 0); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 16: +#line 217 "ftp.y" + { + if (yyvsp[-1]) + send_file_list("."); + } +break; +case 17: +#line 222 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + send_file_list((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 18: +#line 229 "ftp.y" + { + if (yyvsp[-1]) + retrieve("/bin/ls -lgA", ""); + } +break; +case 19: +#line 234 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + retrieve("/bin/ls -lgA %s", (char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 20: +#line 241 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + statfilecmd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 21: +#line 248 "ftp.y" + { + statcmd(); + } +break; +case 22: +#line 252 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + delete((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 23: +#line 259 "ftp.y" + { + if (fromname) { + renamecmd(fromname, (char *) yyvsp[-1]); + free(fromname); + fromname = (char *) 0; + } else { + reply(503, "Bad sequence of commands."); + } + free((char *) yyvsp[-1]); + } +break; +case 24: +#line 270 "ftp.y" + { + reply(225, "ABOR command successful."); + } +break; +case 25: +#line 274 "ftp.y" + { + if (yyvsp[-1]) + cwd(pw->pw_dir); + } +break; +case 26: +#line 279 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + cwd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 27: +#line 286 "ftp.y" + { + help(cmdtab, (char *) 0); + } +break; +case 28: +#line 290 "ftp.y" + { + register char *cp = (char *)yyvsp[-1]; + + if (strncasecmp(cp, "SITE", 4) == 0) { + cp = (char *)yyvsp[-1] + 4; + if (*cp == ' ') + cp++; + if (*cp) + help(sitetab, cp); + else + help(sitetab, (char *) 0); + } else + help(cmdtab, (char *) yyvsp[-1]); + } +break; +case 29: +#line 305 "ftp.y" + { + reply(200, "NOOP command successful."); + } +break; +case 30: +#line 309 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + makedir((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 31: +#line 316 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + removedir((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 32: +#line 323 "ftp.y" + { + if (yyvsp[-1]) + pwd(); + } +break; +case 33: +#line 328 "ftp.y" + { + if (yyvsp[-1]) + cwd(".."); + } +break; +case 34: +#line 333 "ftp.y" + { + help(sitetab, (char *) 0); + } +break; +case 35: +#line 337 "ftp.y" + { + help(sitetab, (char *) yyvsp[-1]); + } +break; +case 36: +#line 341 "ftp.y" + { + int oldmask; + + if (yyvsp[-1]) { + oldmask = umask(0); + (void) umask(oldmask); + reply(200, "Current UMASK is %03o", oldmask); + } + } +break; +case 37: +#line 351 "ftp.y" + { + int oldmask; + + if (yyvsp[-3]) { + if ((yyvsp[-1] == -1) || (yyvsp[-1] > 0777)) { + reply(501, "Bad UMASK value"); + } else { + oldmask = umask(yyvsp[-1]); + reply(200, + "UMASK set to %03o (was %03o)", + yyvsp[-1], oldmask); + } + } + } +break; +case 38: +#line 366 "ftp.y" + { + if (yyvsp[-5] && (yyvsp[-1] != NULL)) { + if (yyvsp[-3] > 0777) + reply(501, + "CHMOD: Mode value must be between 0 and 0777"); + else if (chmod((char *) yyvsp[-1], yyvsp[-3]) < 0) + perror_reply(550, (char *) yyvsp[-1]); + else + reply(200, "CHMOD command successful."); + } + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 39: +#line 380 "ftp.y" + { + reply(200, + "Current IDLE time limit is %d seconds; max %d", + timeout, maxtimeout); + } +break; +case 40: +#line 386 "ftp.y" + { + if (yyvsp[-1] < 30 || yyvsp[-1] > maxtimeout) { + reply(501, + "Maximum IDLE time must be between 30 and %d seconds", + maxtimeout); + } else { + timeout = yyvsp[-1]; + (void) alarm((unsigned) timeout); + reply(200, + "Maximum IDLE time set to %d seconds", + timeout); + } + } +break; +case 41: +#line 400 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + store((char *) yyvsp[-1], "w", 1); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 42: +#line 407 "ftp.y" + { +#ifdef unix +#ifdef BSD + reply(215, "UNIX Type: L%d Version: BSD-%d", + NBBY, BSD); +#else /* BSD */ + reply(215, "UNIX Type: L%d", NBBY); +#endif /* BSD */ +#else /* unix */ + reply(215, "UNKNOWN Type: L%d", NBBY); +#endif /* unix */ + } +break; +case 43: +#line 428 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) + sizecmd((char *) yyvsp[-1]); + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 44: +#line 445 "ftp.y" + { + if (yyvsp[-3] && yyvsp[-1] != NULL) { + struct stat stbuf; + if (stat((char *) yyvsp[-1], &stbuf) < 0) + perror_reply(550, "%s", (char *) yyvsp[-1]); + else if ((stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", + (char *) yyvsp[-1]); + } else { + register struct tm *t; + struct tm *gmtime(); + t = gmtime(&stbuf.st_mtime); + reply(213, + "19%02d%02d%02d%02d%02d%02d", + t->tm_year, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + } + } + if (yyvsp[-1] != NULL) + free((char *) yyvsp[-1]); + } +break; +case 45: +#line 467 "ftp.y" + { + reply(221, "Goodbye."); + dologout(0); + } +break; +case 46: +#line 472 "ftp.y" + { + yyerrok; + } +break; +case 47: +#line 477 "ftp.y" + { + char *renamefrom(); + + if (yyvsp[-3] && yyvsp[-1]) { + fromname = renamefrom((char *) yyvsp[-1]); + if (fromname == (char *) 0 && yyvsp[-1]) { + free((char *) yyvsp[-1]); + } + } + } +break; +case 49: +#line 493 "ftp.y" + { + *(char **)&(yyval) = ""; + } +break; +case 52: +#line 504 "ftp.y" + { + register char *a, *p; + + a = (char *)&data_dest.sin_addr; + a[0] = yyvsp[-10]; a[1] = yyvsp[-8]; a[2] = yyvsp[-6]; a[3] = yyvsp[-4]; + p = (char *)&data_dest.sin_port; + p[0] = yyvsp[-2]; p[1] = yyvsp[0]; + data_dest.sin_family = AF_INET; + } +break; +case 53: +#line 516 "ftp.y" + { + yyval = FORM_N; + } +break; +case 54: +#line 520 "ftp.y" + { + yyval = FORM_T; + } +break; +case 55: +#line 524 "ftp.y" + { + yyval = FORM_C; + } +break; +case 56: +#line 530 "ftp.y" + { + cmd_type = TYPE_A; + cmd_form = FORM_N; + } +break; +case 57: +#line 535 "ftp.y" + { + cmd_type = TYPE_A; + cmd_form = yyvsp[0]; + } +break; +case 58: +#line 540 "ftp.y" + { + cmd_type = TYPE_E; + cmd_form = FORM_N; + } +break; +case 59: +#line 545 "ftp.y" + { + cmd_type = TYPE_E; + cmd_form = yyvsp[0]; + } +break; +case 60: +#line 550 "ftp.y" + { + cmd_type = TYPE_I; + } +break; +case 61: +#line 554 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = NBBY; + } +break; +case 62: +#line 559 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = yyvsp[0]; + } +break; +case 63: +#line 565 "ftp.y" + { + cmd_type = TYPE_L; + cmd_bytesz = yyvsp[0]; + } +break; +case 64: +#line 572 "ftp.y" + { + yyval = STRU_F; + } +break; +case 65: +#line 576 "ftp.y" + { + yyval = STRU_R; + } +break; +case 66: +#line 580 "ftp.y" + { + yyval = STRU_P; + } +break; +case 67: +#line 586 "ftp.y" + { + yyval = MODE_S; + } +break; +case 68: +#line 590 "ftp.y" + { + yyval = MODE_B; + } +break; +case 69: +#line 594 "ftp.y" + { + yyval = MODE_C; + } +break; +case 70: +#line 600 "ftp.y" + { + /* + * Problem: this production is used for all pathname + * processing, but only gives a 550 error reply. + * This is a valid reply in some cases but not in others. + */ + if (logged_in && yyvsp[0] && strncmp((char *) yyvsp[0], "~", 1) == 0) { + *(char **)&(yyval) = *glob((char *) yyvsp[0]); + if (globerr != NULL) { + reply(550, globerr); + yyval = NULL; + } + free((char *) yyvsp[0]); + } else + yyval = yyvsp[0]; + } +break; +case 72: +#line 622 "ftp.y" + { + register int ret, dec, multby, digit; + + /* + * Convert a number that was read as decimal number + * to what it would be if it had been read as octal. + */ + dec = yyvsp[0]; + multby = 1; + ret = 0; + while (dec) { + digit = dec%10; + if (digit > 7) { + ret = -1; + break; + } + ret += digit * multby; + multby *= 8; + dec /= 10; + } + yyval = ret; + } +break; +case 73: +#line 647 "ftp.y" + { + if (logged_in) + yyval = 1; + else { + reply(530, "Please login with USER and PASS."); + yyval = 0; + } + } +break; +#line 1688 "ftp.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/usr.bin/yacc/test/ftp.tab.h b/usr.bin/yacc/test/ftp.tab.h new file mode 100644 index 0000000..24f0791 --- /dev/null +++ b/usr.bin/yacc/test/ftp.tab.h @@ -0,0 +1,63 @@ +#define A 257 +#define B 258 +#define C 259 +#define E 260 +#define F 261 +#define I 262 +#define L 263 +#define N 264 +#define P 265 +#define R 266 +#define S 267 +#define T 268 +#define SP 269 +#define CRLF 270 +#define COMMA 271 +#define STRING 272 +#define NUMBER 273 +#define USER 274 +#define PASS 275 +#define ACCT 276 +#define REIN 277 +#define QUIT 278 +#define PORT 279 +#define PASV 280 +#define TYPE 281 +#define STRU 282 +#define MODE 283 +#define RETR 284 +#define STOR 285 +#define APPE 286 +#define MLFL 287 +#define MAIL 288 +#define MSND 289 +#define MSOM 290 +#define MSAM 291 +#define MRSQ 292 +#define MRCP 293 +#define ALLO 294 +#define REST 295 +#define RNFR 296 +#define RNTO 297 +#define ABOR 298 +#define DELE 299 +#define CWD 300 +#define LIST 301 +#define NLST 302 +#define SITE 303 +#define STAT 304 +#define HELP 305 +#define NOOP 306 +#define MKD 307 +#define RMD 308 +#define PWD 309 +#define CDUP 310 +#define STOU 311 +#define SMNT 312 +#define SYST 313 +#define SIZE 314 +#define MDTM 315 +#define UMASK 316 +#define IDLE 317 +#define CHMOD 318 +#define LEXERR 319 diff --git a/usr.bin/yacc/test/ftp.y b/usr.bin/yacc/test/ftp.y new file mode 100644 index 0000000..a9ee9cd --- /dev/null +++ b/usr.bin/yacc/test/ftp.y @@ -0,0 +1,1180 @@ +/* + * Copyright (c) 1985, 1988 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89 + */ + +/* + * Grammar for FTP commands. + * See RFC 959. + */ + +%{ + +#ifndef lint +static char sccsid[] = "@(#)ftpcmd.y 5.20.1.1 (Berkeley) 3/2/89"; +#endif /* not lint */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern char *globerr; +extern int usedefault; +extern int transflag; +extern char tmpline[]; +char **glob(); + +static int cmd_type; +static int cmd_form; +static int cmd_bytesz; +char cbuf[512]; +char *fromname; + +char *index(); +%} + +%token + A B C E F I + L N P R S T + + SP CRLF COMMA STRING NUMBER + + USER PASS ACCT REIN QUIT PORT + PASV TYPE STRU MODE RETR STOR + APPE MLFL MAIL MSND MSOM MSAM + MRSQ MRCP ALLO REST RNFR RNTO + ABOR DELE CWD LIST NLST SITE + STAT HELP NOOP MKD RMD PWD + CDUP STOU SMNT SYST SIZE MDTM + + UMASK IDLE CHMOD + + LEXERR + +%start cmd_list + +%% + +cmd_list: /* empty */ + | cmd_list cmd + = { + fromname = (char *) 0; + } + | cmd_list rcmd + ; + +cmd: USER SP username CRLF + = { + user((char *) $3); + free((char *) $3); + } + | PASS SP password CRLF + = { + pass((char *) $3); + free((char *) $3); + } + | PORT SP host_port CRLF + = { + usedefault = 0; + if (pdata >= 0) { + (void) close(pdata); + pdata = -1; + } + reply(200, "PORT command successful."); + } + | PASV CRLF + = { + passive(); + } + | TYPE SP type_code CRLF + = { + switch (cmd_type) { + + case TYPE_A: + if (cmd_form == FORM_N) { + reply(200, "Type set to A."); + type = cmd_type; + form = cmd_form; + } else + reply(504, "Form must be N."); + break; + + case TYPE_E: + reply(504, "Type E not implemented."); + break; + + case TYPE_I: + reply(200, "Type set to I."); + type = cmd_type; + break; + + case TYPE_L: +#if NBBY == 8 + if (cmd_bytesz == 8) { + reply(200, + "Type set to L (byte size 8)."); + type = cmd_type; + } else + reply(504, "Byte size must be 8."); +#else /* NBBY == 8 */ + UNIMPLEMENTED for NBBY != 8 +#endif /* NBBY == 8 */ + } + } + | STRU SP struct_code CRLF + = { + switch ($3) { + + case STRU_F: + reply(200, "STRU F ok."); + break; + + default: + reply(504, "Unimplemented STRU type."); + } + } + | MODE SP mode_code CRLF + = { + switch ($3) { + + case MODE_S: + reply(200, "MODE S ok."); + break; + + default: + reply(502, "Unimplemented MODE type."); + } + } + | ALLO SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | ALLO SP NUMBER SP R SP NUMBER CRLF + = { + reply(202, "ALLO command ignored."); + } + | RETR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve((char *) 0, (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STOR check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 0); + if ($4 != NULL) + free((char *) $4); + } + | APPE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "a", 0); + if ($4 != NULL) + free((char *) $4); + } + | NLST check_login CRLF + = { + if ($2) + send_file_list("."); + } + | NLST check_login SP STRING CRLF + = { + if ($2 && $4 != NULL) + send_file_list((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | LIST check_login CRLF + = { + if ($2) + retrieve("/bin/ls -lgA", ""); + } + | LIST check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + retrieve("/bin/ls -lgA %s", (char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + statfilecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | STAT CRLF + = { + statcmd(); + } + | DELE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + delete((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RNTO SP pathname CRLF + = { + if (fromname) { + renamecmd(fromname, (char *) $3); + free(fromname); + fromname = (char *) 0; + } else { + reply(503, "Bad sequence of commands."); + } + free((char *) $3); + } + | ABOR CRLF + = { + reply(225, "ABOR command successful."); + } + | CWD check_login CRLF + = { + if ($2) + cwd(pw->pw_dir); + } + | CWD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + cwd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | HELP CRLF + = { + help(cmdtab, (char *) 0); + } + | HELP SP STRING CRLF + = { + register char *cp = (char *)$3; + + if (strncasecmp(cp, "SITE", 4) == 0) { + cp = (char *)$3 + 4; + if (*cp == ' ') + cp++; + if (*cp) + help(sitetab, cp); + else + help(sitetab, (char *) 0); + } else + help(cmdtab, (char *) $3); + } + | NOOP CRLF + = { + reply(200, "NOOP command successful."); + } + | MKD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + makedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | RMD check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + removedir((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + | PWD check_login CRLF + = { + if ($2) + pwd(); + } + | CDUP check_login CRLF + = { + if ($2) + cwd(".."); + } + | SITE SP HELP CRLF + = { + help(sitetab, (char *) 0); + } + | SITE SP HELP SP STRING CRLF + = { + help(sitetab, (char *) $5); + } + | SITE SP UMASK check_login CRLF + = { + int oldmask; + + if ($4) { + oldmask = umask(0); + (void) umask(oldmask); + reply(200, "Current UMASK is %03o", oldmask); + } + } + | SITE SP UMASK check_login SP octal_number CRLF + = { + int oldmask; + + if ($4) { + if (($6 == -1) || ($6 > 0777)) { + reply(501, "Bad UMASK value"); + } else { + oldmask = umask($6); + reply(200, + "UMASK set to %03o (was %03o)", + $6, oldmask); + } + } + } + | SITE SP CHMOD check_login SP octal_number SP pathname CRLF + = { + if ($4 && ($8 != NULL)) { + if ($6 > 0777) + reply(501, + "CHMOD: Mode value must be between 0 and 0777"); + else if (chmod((char *) $8, $6) < 0) + perror_reply(550, (char *) $8); + else + reply(200, "CHMOD command successful."); + } + if ($8 != NULL) + free((char *) $8); + } + | SITE SP IDLE CRLF + = { + reply(200, + "Current IDLE time limit is %d seconds; max %d", + timeout, maxtimeout); + } + | SITE SP IDLE SP NUMBER CRLF + = { + if ($5 < 30 || $5 > maxtimeout) { + reply(501, + "Maximum IDLE time must be between 30 and %d seconds", + maxtimeout); + } else { + timeout = $5; + (void) alarm((unsigned) timeout); + reply(200, + "Maximum IDLE time set to %d seconds", + timeout); + } + } + | STOU check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + store((char *) $4, "w", 1); + if ($4 != NULL) + free((char *) $4); + } + | SYST CRLF + = { +#ifdef unix +#ifdef BSD + reply(215, "UNIX Type: L%d Version: BSD-%d", + NBBY, BSD); +#else /* BSD */ + reply(215, "UNIX Type: L%d", NBBY); +#endif /* BSD */ +#else /* unix */ + reply(215, "UNKNOWN Type: L%d", NBBY); +#endif /* unix */ + } + + /* + * SIZE is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return size of file in a format suitable for + * using with RESTART (we just count bytes). + */ + | SIZE check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) + sizecmd((char *) $4); + if ($4 != NULL) + free((char *) $4); + } + + /* + * MDTM is not in RFC959, but Postel has blessed it and + * it will be in the updated RFC. + * + * Return modification time of file as an ISO 3307 + * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx + * where xxx is the fractional second (of any precision, + * not necessarily 3 digits) + */ + | MDTM check_login SP pathname CRLF + = { + if ($2 && $4 != NULL) { + struct stat stbuf; + if (stat((char *) $4, &stbuf) < 0) + perror_reply(550, "%s", (char *) $4); + else if ((stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", + (char *) $4); + } else { + register struct tm *t; + struct tm *gmtime(); + t = gmtime(&stbuf.st_mtime); + reply(213, + "19%02d%02d%02d%02d%02d%02d", + t->tm_year, t->tm_mon+1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + } + } + if ($4 != NULL) + free((char *) $4); + } + | QUIT CRLF + = { + reply(221, "Goodbye."); + dologout(0); + } + | error CRLF + = { + yyerrok; + } + ; +rcmd: RNFR check_login SP pathname CRLF + = { + char *renamefrom(); + + if ($2 && $4) { + fromname = renamefrom((char *) $4); + if (fromname == (char *) 0 && $4) { + free((char *) $4); + } + } + } + ; + +username: STRING + ; + +password: /* empty */ + = { + *(char **)&($$) = ""; + } + | STRING + ; + +byte_size: NUMBER + ; + +host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA + NUMBER COMMA NUMBER + = { + register char *a, *p; + + a = (char *)&data_dest.sin_addr; + a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; + p = (char *)&data_dest.sin_port; + p[0] = $9; p[1] = $11; + data_dest.sin_family = AF_INET; + } + ; + +form_code: N + = { + $$ = FORM_N; + } + | T + = { + $$ = FORM_T; + } + | C + = { + $$ = FORM_C; + } + ; + +type_code: A + = { + cmd_type = TYPE_A; + cmd_form = FORM_N; + } + | A SP form_code + = { + cmd_type = TYPE_A; + cmd_form = $3; + } + | E + = { + cmd_type = TYPE_E; + cmd_form = FORM_N; + } + | E SP form_code + = { + cmd_type = TYPE_E; + cmd_form = $3; + } + | I + = { + cmd_type = TYPE_I; + } + | L + = { + cmd_type = TYPE_L; + cmd_bytesz = NBBY; + } + | L SP byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $3; + } + /* this is for a bug in the BBN ftp */ + | L byte_size + = { + cmd_type = TYPE_L; + cmd_bytesz = $2; + } + ; + +struct_code: F + = { + $$ = STRU_F; + } + | R + = { + $$ = STRU_R; + } + | P + = { + $$ = STRU_P; + } + ; + +mode_code: S + = { + $$ = MODE_S; + } + | B + = { + $$ = MODE_B; + } + | C + = { + $$ = MODE_C; + } + ; + +pathname: pathstring + = { + /* + * Problem: this production is used for all pathname + * processing, but only gives a 550 error reply. + * This is a valid reply in some cases but not in others. + */ + if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { + *(char **)&($$) = *glob((char *) $1); + if (globerr != NULL) { + reply(550, globerr); + $$ = NULL; + } + free((char *) $1); + } else + $$ = $1; + } + ; + +pathstring: STRING + ; + +octal_number: NUMBER + = { + register int ret, dec, multby, digit; + + /* + * Convert a number that was read as decimal number + * to what it would be if it had been read as octal. + */ + dec = $1; + multby = 1; + ret = 0; + while (dec) { + digit = dec%10; + if (digit > 7) { + ret = -1; + break; + } + ret += digit * multby; + multby *= 8; + dec /= 10; + } + $$ = ret; + } + ; + +check_login: /* empty */ + = { + if (logged_in) + $$ = 1; + else { + reply(530, "Please login with USER and PASS."); + $$ = 0; + } + } + ; + +%% + +extern jmp_buf errcatch; + +#define CMD 0 /* beginning of command */ +#define ARGS 1 /* expect miscellaneous arguments */ +#define STR1 2 /* expect SP followed by STRING */ +#define STR2 3 /* expect STRING */ +#define OSTR 4 /* optional SP then STRING */ +#define ZSTR1 5 /* SP then optional STRING */ +#define ZSTR2 6 /* optional STRING after SP */ +#define SITECMD 7 /* SITE command */ +#define NSTR 8 /* Number followed by a string */ + +struct tab { + char *name; + short token; + short state; + short implemented; /* 1 if command is implemented */ + char *help; +}; + +struct tab cmdtab[] = { /* In order defined in RFC 765 */ + { "USER", USER, STR1, 1, " username" }, + { "PASS", PASS, ZSTR1, 1, " password" }, + { "ACCT", ACCT, STR1, 0, "(specify account)" }, + { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, + { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, + { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, + { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, + { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, + { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, + { "STRU", STRU, ARGS, 1, "(specify file structure)" }, + { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, + { "RETR", RETR, STR1, 1, " file-name" }, + { "STOR", STOR, STR1, 1, " file-name" }, + { "APPE", APPE, STR1, 1, " file-name" }, + { "MLFL", MLFL, OSTR, 0, "(mail file)" }, + { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, + { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, + { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, + { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, + { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, + { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, + { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, + { "REST", REST, ARGS, 0, "(restart command)" }, + { "RNFR", RNFR, STR1, 1, " file-name" }, + { "RNTO", RNTO, STR1, 1, " file-name" }, + { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, + { "DELE", DELE, STR1, 1, " file-name" }, + { "CWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "XCWD", CWD, OSTR, 1, "[ directory-name ]" }, + { "LIST", LIST, OSTR, 1, "[ path-name ]" }, + { "NLST", NLST, OSTR, 1, "[ path-name ]" }, + { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, + { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, + { "STAT", STAT, OSTR, 1, "[ path-name ]" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { "NOOP", NOOP, ARGS, 1, "" }, + { "MKD", MKD, STR1, 1, " path-name" }, + { "XMKD", MKD, STR1, 1, " path-name" }, + { "RMD", RMD, STR1, 1, " path-name" }, + { "XRMD", RMD, STR1, 1, " path-name" }, + { "PWD", PWD, ARGS, 1, "(return current directory)" }, + { "XPWD", PWD, ARGS, 1, "(return current directory)" }, + { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, + { "STOU", STOU, STR1, 1, " file-name" }, + { "SIZE", SIZE, OSTR, 1, " path-name" }, + { "MDTM", MDTM, OSTR, 1, " path-name" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab sitetab[] = { + { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, + { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, + { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, + { "HELP", HELP, OSTR, 1, "[ ]" }, + { NULL, 0, 0, 0, 0 } +}; + +struct tab * +lookup(p, cmd) + register struct tab *p; + char *cmd; +{ + + for (; p->name != NULL; p++) + if (strcmp(cmd, p->name) == 0) + return (p); + return (0); +} + +#include + +/* + * getline - a hacked up version of fgets to ignore TELNET escape codes. + */ +char * +getline(s, n, iop) + char *s; + register FILE *iop; +{ + register c; + register char *cs; + + cs = s; +/* tmpline may contain saved command from urgent mode interruption */ + for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { + *cs++ = tmpline[c]; + if (tmpline[c] == '\n') { + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + tmpline[0] = '\0'; + return(s); + } + if (c == 0) + tmpline[0] = '\0'; + } + while ((c = getc(iop)) != EOF) { + c &= 0377; + if (c == IAC) { + if ((c = getc(iop)) != EOF) { + c &= 0377; + switch (c) { + case WILL: + case WONT: + c = getc(iop); + printf("%c%c%c", IAC, DONT, 0377&c); + (void) fflush(stdout); + continue; + case DO: + case DONT: + c = getc(iop); + printf("%c%c%c", IAC, WONT, 0377&c); + (void) fflush(stdout); + continue; + case IAC: + break; + default: + continue; /* ignore command */ + } + } + } + *cs++ = c; + if (--n <= 0 || c == '\n') + break; + } + if (c == EOF && cs == s) + return (NULL); + *cs++ = '\0'; + if (debug) + syslog(LOG_DEBUG, "command: %s", s); + return (s); +} + +static int +toolong() +{ + time_t now; + extern char *ctime(); + extern time_t time(); + + reply(421, + "Timeout (%d seconds): closing control connection.", timeout); + (void) time(&now); + if (logging) { + syslog(LOG_INFO, + "User %s timed out after %d seconds at %s", + (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); + } + dologout(1); +} + +yylex() +{ + static int cpos, state; + register char *cp, *cp2; + register struct tab *p; + int n; + char c, *strpbrk(); + char *copy(); + + for (;;) { + switch (state) { + + case CMD: + (void) signal(SIGALRM, toolong); + (void) alarm((unsigned) timeout); + if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + reply(221, "You could at least say goodbye."); + dologout(0); + } + (void) alarm(0); +#ifdef SETPROCTITLE + if (strncasecmp(cbuf, "PASS", 4) != NULL) + setproctitle("%s: %s", proctitle, cbuf); +#endif /* SETPROCTITLE */ + if ((cp = index(cbuf, '\r'))) { + *cp++ = '\n'; + *cp = '\0'; + } + if ((cp = strpbrk(cbuf, " \n"))) + cpos = cp - cbuf; + if (cpos == 0) + cpos = 4; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cbuf); + p = lookup(cmdtab, cbuf); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + break; + + case SITECMD: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + cp = &cbuf[cpos]; + if ((cp2 = strpbrk(cp, " \n"))) + cpos = cp2 - cbuf; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + upper(cp); + p = lookup(sitetab, cp); + cbuf[cpos] = c; + if (p != 0) { + if (p->implemented == 0) { + state = CMD; + nack(p->name); + longjmp(errcatch,0); + /* NOTREACHED */ + } + state = p->state; + *(char **)&yylval = p->name; + return (p->token); + } + state = CMD; + break; + + case OSTR: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR1: + case ZSTR1: + dostr1: + if (cbuf[cpos] == ' ') { + cpos++; + state = state == OSTR ? STR2 : ++state; + return (SP); + } + break; + + case ZSTR2: + if (cbuf[cpos] == '\n') { + state = CMD; + return (CRLF); + } + /* FALLTHROUGH */ + + case STR2: + cp = &cbuf[cpos]; + n = strlen(cp); + cpos += n - 1; + /* + * Make sure the string is nonempty and \n terminated. + */ + if (n > 1 && cbuf[cpos] == '\n') { + cbuf[cpos] = '\0'; + *(char **)&yylval = copy(cp); + cbuf[cpos] = '\n'; + state = ARGS; + return (STRING); + } + break; + + case NSTR: + if (cbuf[cpos] == ' ') { + cpos++; + return (SP); + } + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + state = STR1; + return (NUMBER); + } + state = STR1; + goto dostr1; + + case ARGS: + if (isdigit(cbuf[cpos])) { + cp = &cbuf[cpos]; + while (isdigit(cbuf[++cpos])) + ; + c = cbuf[cpos]; + cbuf[cpos] = '\0'; + yylval = atoi(cp); + cbuf[cpos] = c; + return (NUMBER); + } + switch (cbuf[cpos++]) { + + case '\n': + state = CMD; + return (CRLF); + + case ' ': + return (SP); + + case ',': + return (COMMA); + + case 'A': + case 'a': + return (A); + + case 'B': + case 'b': + return (B); + + case 'C': + case 'c': + return (C); + + case 'E': + case 'e': + return (E); + + case 'F': + case 'f': + return (F); + + case 'I': + case 'i': + return (I); + + case 'L': + case 'l': + return (L); + + case 'N': + case 'n': + return (N); + + case 'P': + case 'p': + return (P); + + case 'R': + case 'r': + return (R); + + case 'S': + case 's': + return (S); + + case 'T': + case 't': + return (T); + + } + break; + + default: + fatal("Unknown state in scanner."); + } + yyerror((char *) 0); + state = CMD; + longjmp(errcatch,0); + } +} + +upper(s) + register char *s; +{ + while (*s != '\0') { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +char * +copy(s) + char *s; +{ + char *p; + extern char *malloc(), *strcpy(); + + p = malloc((unsigned) strlen(s) + 1); + if (p == NULL) + fatal("Ran out of memory."); + (void) strcpy(p, s); + return (p); +} + +help(ctab, s) + struct tab *ctab; + char *s; +{ + register struct tab *c; + register int width, NCMDS; + char *type; + + if (ctab == sitetab) + type = "SITE "; + else + type = ""; + width = 0, NCMDS = 0; + for (c = ctab; c->name != NULL; c++) { + int len = strlen(c->name); + + if (len > width) + width = len; + NCMDS++; + } + width = (width + 8) &~ 7; + if (s == 0) { + register int i, j, w; + int columns, lines; + + lreply(214, "The following %scommands are recognized %s.", + type, "(* =>'s unimplemented)"); + columns = 76 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + printf(" "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + printf("%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + putchar(' '); + w++; + } + } + printf("\r\n"); + } + (void) fflush(stdout); + reply(214, "Direct comments to ftp-bugs@%s.", hostname); + return; + } + upper(s); + c = lookup(ctab, s); + if (c == (struct tab *)0) { + reply(502, "Unknown command %s.", s); + return; + } + if (c->implemented) + reply(214, "Syntax: %s%s %s", type, c->name, c->help); + else + reply(214, "%s%-*s\t%s; unimplemented.", type, width, + c->name, c->help); +} + +sizecmd(filename) +char *filename; +{ + switch (type) { + case TYPE_L: + case TYPE_I: { + struct stat stbuf; + if (stat(filename, &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) + reply(550, "%s: not a plain file.", filename); + else + reply(213, "%lu", stbuf.st_size); + break;} + case TYPE_A: { + FILE *fin; + register int c, count; + struct stat stbuf; + fin = fopen(filename, "r"); + if (fin == NULL) { + perror_reply(550, filename); + return; + } + if (fstat(fileno(fin), &stbuf) < 0 || + (stbuf.st_mode&S_IFMT) != S_IFREG) { + reply(550, "%s: not a plain file.", filename); + (void) fclose(fin); + return; + } + + count = 0; + while((c=getc(fin)) != EOF) { + if (c == '\n') /* will get expanded to \r\n */ + count++; + count++; + } + (void) fclose(fin); + + reply(213, "%ld", count); + break;} + default: + reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); + } +} diff --git a/usr.bin/yacc/verbose.c b/usr.bin/yacc/verbose.c new file mode 100644 index 0000000..33ae265 --- /dev/null +++ b/usr.bin/yacc/verbose.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)verbose.c 5.3 (Berkeley) 1/20/91"; +#endif /* not lint */ + +#include "defs.h" + +static short *null_rules; + +verbose() +{ + register int i; + + if (!vflag) return; + + null_rules = (short *) MALLOC(nrules*sizeof(short)); + if (null_rules == 0) no_space(); + fprintf(verbose_file, "\f\n"); + for (i = 0; i < nstates; i++) + print_state(i); + FREE(null_rules); + + if (nunused) + log_unused(); + if (SRtotal || RRtotal) + log_conflicts(); + + fprintf(verbose_file, "\n\n%d terminals, %d nonterminals\n", ntokens, + nvars); + fprintf(verbose_file, "%d grammar rules, %d states\n", nrules - 2, nstates); +} + + +log_unused() +{ + register int i; + register short *p; + + fprintf(verbose_file, "\n\nRules never reduced:\n"); + for (i = 3; i < nrules; ++i) + { + if (!rules_used[i]) + { + fprintf(verbose_file, "\t%s :", symbol_name[rlhs[i]]); + for (p = ritem + rrhs[i]; *p >= 0; ++p) + fprintf(verbose_file, " %s", symbol_name[*p]); + fprintf(verbose_file, " (%d)\n", i - 2); + } + } +} + + +log_conflicts() +{ + register int i; + + fprintf(verbose_file, "\n\n"); + for (i = 0; i < nstates; i++) + { + if (SRconflicts[i] || RRconflicts[i]) + { + fprintf(verbose_file, "State %d contains ", i); + if (SRconflicts[i] == 1) + fprintf(verbose_file, "1 shift/reduce conflict"); + else if (SRconflicts[i] > 1) + fprintf(verbose_file, "%d shift/reduce conflicts", + SRconflicts[i]); + if (SRconflicts[i] && RRconflicts[i]) + fprintf(verbose_file, ", "); + if (RRconflicts[i] == 1) + fprintf(verbose_file, "1 reduce/reduce conflict"); + else if (RRconflicts[i] > 1) + fprintf(verbose_file, "%d reduce/reduce conflicts", + RRconflicts[i]); + fprintf(verbose_file, ".\n"); + } + } +} + + +print_state(state) +int state; +{ + if (state) + fprintf(verbose_file, "\n\n"); + if (SRconflicts[state] || RRconflicts[state]) + print_conflicts(state); + fprintf(verbose_file, "state %d\n", state); + print_core(state); + print_nulls(state); + print_actions(state); +} + + +print_conflicts(state) +int state; +{ + register int symbol, act, number; + register action *p; + + symbol = -1; + for (p = parser[state]; p; p = p->next) + { + if (p->suppressed == 2) + continue; + + if (p->symbol != symbol) + { + symbol = p->symbol; + number = p->number; + if (p->action_code == SHIFT) + act = SHIFT; + else + act = REDUCE; + } + else if (p->suppressed == 1) + { + if (state == final_state && symbol == 0) + { + fprintf(verbose_file, "%d: shift/reduce conflict \ +(accept, reduce %d) on $end\n", state, p->number - 2); + } + else + { + if (act == SHIFT) + { + fprintf(verbose_file, "%d: shift/reduce conflict \ +(shift %d, reduce %d) on %s\n", state, number, p->number - 2, + symbol_name[symbol]); + } + else + { + fprintf(verbose_file, "%d: reduce/reduce conflict \ +(reduce %d, reduce %d) on %s\n", state, number - 2, p->number - 2, + symbol_name[symbol]); + } + } + } + } +} + + +print_core(state) +int state; +{ + register int i; + register int k; + register int rule; + register core *statep; + register short *sp; + register short *sp1; + + statep = state_table[state]; + k = statep->nitems; + + for (i = 0; i < k; i++) + { + sp1 = sp = ritem + statep->items[i]; + + while (*sp >= 0) ++sp; + rule = -(*sp); + fprintf(verbose_file, "\t%s : ", symbol_name[rlhs[rule]]); + + for (sp = ritem + rrhs[rule]; sp < sp1; sp++) + fprintf(verbose_file, "%s ", symbol_name[*sp]); + + putc('.', verbose_file); + + while (*sp >= 0) + { + fprintf(verbose_file, " %s", symbol_name[*sp]); + sp++; + } + fprintf(verbose_file, " (%d)\n", -2 - *sp); + } +} + + +print_nulls(state) +int state; +{ + register action *p; + register int i, j, k, nnulls; + + nnulls = 0; + for (p = parser[state]; p; p = p->next) + { + if (p->action_code == REDUCE && + (p->suppressed == 0 || p->suppressed == 1)) + { + i = p->number; + if (rrhs[i] + 1 == rrhs[i+1]) + { + for (j = 0; j < nnulls && i > null_rules[j]; ++j) + continue; + + if (j == nnulls) + { + ++nnulls; + null_rules[j] = i; + } + else if (i != null_rules[j]) + { + ++nnulls; + for (k = nnulls - 1; k > j; --k) + null_rules[k] = null_rules[k-1]; + null_rules[j] = i; + } + } + } + } + + for (i = 0; i < nnulls; ++i) + { + j = null_rules[i]; + fprintf(verbose_file, "\t%s : . (%d)\n", symbol_name[rlhs[j]], + j - 2); + } + fprintf(verbose_file, "\n"); +} + + +print_actions(stateno) +int stateno; +{ + register action *p; + register shifts *sp; + register int as; + + if (stateno == final_state) + fprintf(verbose_file, "\t$end accept\n"); + + p = parser[stateno]; + if (p) + { + print_shifts(p); + print_reductions(p, defred[stateno]); + } + + sp = shift_table[stateno]; + if (sp && sp->nshifts > 0) + { + as = accessing_symbol[sp->shift[sp->nshifts - 1]]; + if (ISVAR(as)) + print_gotos(stateno); + } +} + + +print_shifts(p) +register action *p; +{ + register int count; + register action *q; + + count = 0; + for (q = p; q; q = q->next) + { + if (q->suppressed < 2 && q->action_code == SHIFT) + ++count; + } + + if (count > 0) + { + for (; p; p = p->next) + { + if (p->action_code == SHIFT && p->suppressed == 0) + fprintf(verbose_file, "\t%s shift %d\n", + symbol_name[p->symbol], p->number); + } + } +} + + +print_reductions(p, defred) +register action *p; +register int defred; +{ + register int k, anyreds; + register action *q; + + anyreds = 0; + for (q = p; q ; q = q->next) + { + if (q->action_code == REDUCE && q->suppressed < 2) + { + anyreds = 1; + break; + } + } + + if (anyreds == 0) + fprintf(verbose_file, "\t. error\n"); + else + { + for (; p; p = p->next) + { + if (p->action_code == REDUCE && p->number != defred) + { + k = p->number - 2; + if (p->suppressed == 0) + fprintf(verbose_file, "\t%s reduce %d\n", + symbol_name[p->symbol], k); + } + } + + if (defred > 0) + fprintf(verbose_file, "\t. reduce %d\n", defred - 2); + } +} + + +print_gotos(stateno) +int stateno; +{ + register int i, k; + register int as; + register short *to_state; + register shifts *sp; + + putc('\n', verbose_file); + sp = shift_table[stateno]; + to_state = sp->shift; + for (i = 0; i < sp->nshifts; ++i) + { + k = to_state[i]; + as = accessing_symbol[k]; + if (ISVAR(as)) + fprintf(verbose_file, "\t%s goto %d\n", symbol_name[as], k); + } +} diff --git a/usr.bin/yacc/warshall.c b/usr.bin/yacc/warshall.c new file mode 100644 index 0000000..4672244 --- /dev/null +++ b/usr.bin/yacc/warshall.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Paul Corbett. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (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[] = "@(#)warshall.c 5.4 (Berkeley) 5/24/93"; +#endif /* not lint */ + +#include "defs.h" + +transitive_closure(R, n) +unsigned *R; +int n; +{ + register int rowsize; + register unsigned i; + register unsigned *rowj; + register unsigned *rp; + register unsigned *rend; + register unsigned *ccol; + register unsigned *relend; + register unsigned *cword; + register unsigned *rowi; + + rowsize = WORDSIZE(n); + relend = R + n*rowsize; + + cword = R; + i = 0; + rowi = R; + while (rowi < relend) + { + ccol = cword; + rowj = R; + + while (rowj < relend) + { + if (*ccol & (1 << i)) + { + rp = rowi; + rend = rowj + rowsize; + while (rowj < rend) + *rowj++ |= *rp++; + } + else + { + rowj += rowsize; + } + + ccol += rowsize; + } + + if (++i >= BITS_PER_WORD) + { + i = 0; + cword++; + } + + rowi += rowsize; + } +} + +reflexive_transitive_closure(R, n) +unsigned *R; +int n; +{ + register int rowsize; + register unsigned i; + register unsigned *rp; + register unsigned *relend; + + transitive_closure(R, n); + + rowsize = WORDSIZE(n); + relend = R + n*rowsize; + + i = 0; + rp = R; + while (rp < relend) + { + *rp |= (1 << i); + if (++i >= BITS_PER_WORD) + { + i = 0; + rp++; + } + + rp += rowsize; + } +} diff --git a/usr.bin/yacc/yacc.1 b/usr.bin/yacc/yacc.1 new file mode 100644 index 0000000..787dc00 --- /dev/null +++ b/usr.bin/yacc/yacc.1 @@ -0,0 +1,145 @@ +.\" Copyright (c) 1989, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Paul Corbett. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)yacc.1 5.8 (Berkeley) 5/24/93 +.\" +.TH YACC 1 "May 24, 1993" +.UC 6 +.SH NAME +yacc \- an LALR(1) parser generator +.SH SYNOPSIS +.B yacc [ -dlrtv ] [ -b +.I file_prefix +.B ] [ -p +.I symbol_prefix +.B ] +.I filename +.SH DESCRIPTION +.I Yacc +reads the grammar specification in the file +.I filename +and generates an LR(1) parser for it. +The parsers consist of a set of LALR(1) parsing tables and a driver routine +written in the C programming language. +.I Yacc +normally writes the parse tables and the driver routine to the file +.IR y.tab.c. +.PP +The following options are available: +.RS +.TP +\fB-b \fIfile_prefix\fR +The +.B -b +option changes the prefix prepended to the output file names to +the string denoted by +.IR file_prefix. +The default prefix is the character +.IR y. +.TP +.B -d +The \fB-d\fR option causes the header file +.IR y.tab.h +to be written. +.TP +.B -l +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 +generated code to the user's original code. +If the \fB-l\fR option is specified, +.I yacc +will not insert the #line directives. +Any #line directives specified by the user will be retained. +.TP +\fB-p \fIsymbol_prefix\fR +The +.B -p +option changes the prefix prepended to yacc-generated symbols to +the string denoted by +.IR symbol_prefix. +The default prefix is the string +.IR yy. +.TP +.B -r +The +.B -r +option causes +.I yacc +to produce separate files for code and tables. The code file +is named +.IR y.code.c, +and the tables file is named +.IR y.tab.c. +.TP +.B -t +The +.B -t +option changes the preprocessor directives generated by +.I yacc +so that debugging statements will be incorporated in the compiled code. +.TP +.B -v +The +.B -v +option causes a human-readable description of the generated parser to +be written to the file +.IR y.output. +.RE +.PP +If the environment variable TMPDIR is set, the string denoted by +TMPDIR will be used as the name of the directory where the temporary +files are created. +.SH FILES +.IR y.code.c +.br +.IR y.tab.c +.br +.IR y.tab.h +.br +.IR y.output +.br +.IR /tmp/yacc.aXXXXXX +.br +.IR /tmp/yacc.tXXXXXX +.br +.IR /tmp/yacc.uXXXXXX +.SH DIAGNOSTICS +If there are rules that are never reduced, the number of such rules is +reported on standard error. +If there are any LALR(1) conflicts, the number of conflicts is reported +on standard error. diff --git a/usr.bin/yacc/yyfix.1 b/usr.bin/yacc/yyfix.1 new file mode 100644 index 0000000..7af0a9e --- /dev/null +++ b/usr.bin/yacc/yyfix.1 @@ -0,0 +1,112 @@ +.\" 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. +.\" +.\" @(#)yyfix.1 5.4 (Berkeley) 3/23/93 +.\" +.Dd March 23, 1993 +.Dt YYFIX 1 +.Os BSD 4.4 +.Sh NAME +.Nm yyfix +.Nd extract tables from y.tab.c +.Sh SYNOPSIS +.Nm yyfix +.Ar file +.Op Ar tables +.Sh DESCRIPTION +Programs have historically used a script (often named ``:yyfix'') to +extract tables from the +.Xr yacc 1 +generated file +.Pa y.tab.c . +As the names of the tables generated by the current version of +.Xr yacc +are different from those of historical versions of +.Xr yacc , +the shell script +.Nm yyfix +is provided to simplify the transition. +.Pp +The first (and required) argument to +.Nm yyfix +is the name of the file where the extracted tables should be stored. +.Pp +If further command line arguments are specified, they are taken as +the list of tables to be extracted. +Otherwise, +.Nm yyfix +attempts to determine if the +.Pa y.tab.c +file is from an old or new +.Xr yacc , +and extracts the appropriate tables. +.Pp +The tables +.Dq yyexca , +.Dq yyact , +.Dq yypact , +.Dq yypgo , +.Dq yyr1 , +.Dq yyr2 , +.Dq yychk , +and +.Dq yydef +are extracted +from historical versions of +.Xr yacc . +.Pp +The tables +.Dq yylhs , +.Dq yylen , +.Dq yydefred , +.Dq yydgoto , +.Dq yysindex , +.Dq yyrindex , +.Dq yygindex , +.Dq yytable , +.Dq yyname , +.Dq yyrule , +and +.Dq yycheck , +are extracted from the current version of +.Xr yacc . +.Sh FILES +.Bl -tag -width y.tab.c +.It Pa y.tab.c +File from which tables are extracted. +.El +.Sh SEE ALSO +.Xr yacc 1 +.Sh HISTORY +The +.Nm +command appears in +.Bx 4.4 . diff --git a/usr.bin/yacc/yyfix.sh b/usr.bin/yacc/yyfix.sh new file mode 100644 index 0000000..29085f9 --- /dev/null +++ b/usr.bin/yacc/yyfix.sh @@ -0,0 +1,71 @@ +#!/bin/sh - +# +# 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. +# +# @(#)yyfix.sh 5.2 (Berkeley) 5/12/90 +# +OLDYACC="yyexca yyact yypact yypgo yyr1 yyr2 yychk yydef" +NEWYACC="yylhs yylen yydefred yydgoto yysindex yyrindex yygindex \ + yytable yycheck" + +file=$1 +>$file +shift + +if [ $# -eq 0 ] ; then + if grep yylhs y.tab.c > /dev/null ; then + if grep yyname y.tab.c > /dev/null ; then + NEWYACC="$NEWYACC yyname" + fi + if grep yyrule y.tab.c > /dev/null ; then + NEWYACC="$NEWYACC yyrule" + fi + set $NEWYACC + else + set $OLDYACC + fi +fi + +for i +do +ed - y.tab.c << END +/^\(.*\)$i[ ]*\[]/s//extern \1 $i[];\\ +\1 $i []/ +.ka +/}/kb +'br $file +'a,.w $file +'a,.d +w +q +END +done diff --git a/usr.bin/yes/Makefile b/usr.bin/yes/Makefile new file mode 100644 index 0000000..1a1c3c0 --- /dev/null +++ b/usr.bin/yes/Makefile @@ -0,0 +1,5 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= yes + +.include diff --git a/usr.bin/yes/yes.1 b/usr.bin/yes/yes.1 new file mode 100644 index 0000000..c83b9bb --- /dev/null +++ b/usr.bin/yes/yes.1 @@ -0,0 +1,54 @@ +.\" Copyright (c) 1980, 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. +.\" +.\" @(#)yes.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt YES 1 +.Os BSD 4 +.Sh NAME +.Nm yes +.Nd be repetitively affirmative +.Sh SYNOPSIS +.Nm yes +.Op Ar expletive +.Sh DESCRIPTION +.Nm Yes +outputs +.Ar expletive , +or, by default, +.Dq y , +forever. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/usr.bin/yes/yes.c b/usr.bin/yes/yes.c new file mode 100644 index 0000000..5e1edd6 --- /dev/null +++ b/usr.bin/yes/yes.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1987, 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 copyright[] = +"@(#) Copyright (c) 1987, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)yes.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +main(argc, argv) + int argc; + char **argv; +{ + if (argc > 1) + for(;;) + puts(argv[1]); + else for (;;) + puts("y"); +} -- cgit v1.1